diff options
author | Juan J. Martinez <jjm@usebox.net> | 2023-11-05 11:22:55 +0000 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2023-11-05 11:31:28 +0000 |
commit | 2fbdf974338bde8576efdae40a819a76b2391033 (patch) | |
tree | 64d41a37470143f142344f9a439d96de3e7918c2 /tools/rasm_src | |
download | kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.tar.gz kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.zip |
Initial import of the open source release
Diffstat (limited to 'tools/rasm_src')
-rw-r--r-- | tools/rasm_src/Makefile | 11 | ||||
-rw-r--r-- | tools/rasm_src/decrunch/aplib_z80_todo.asm | 190 | ||||
-rw-r--r-- | tools/rasm_src/decrunch/deexo.asm | 118 | ||||
-rw-r--r-- | tools/rasm_src/decrunch/dzx7_turbo.asm | 80 | ||||
-rw-r--r-- | tools/rasm_src/decrunch/exomizer3megachur.asm | 210 | ||||
-rw-r--r-- | tools/rasm_src/decrunch/lz48decrunch_v006.asm | 113 | ||||
-rw-r--r-- | tools/rasm_src/decrunch/lz49decrunch_v001.asm | 138 | ||||
-rw-r--r-- | tools/rasm_src/decrunch/lz4_docent.asm | 118 | ||||
-rw-r--r-- | tools/rasm_src/exomizer.h | 4942 | ||||
-rw-r--r-- | tools/rasm_src/lz4.h | 3329 | ||||
-rw-r--r-- | tools/rasm_src/minilib.h | 1151 | ||||
-rw-r--r-- | tools/rasm_src/rasm.h | 26 | ||||
-rw-r--r-- | tools/rasm_src/rasm_v0119.c | 17316 | ||||
-rw-r--r-- | tools/rasm_src/zx7.h | 293 |
14 files changed, 28035 insertions, 0 deletions
diff --git a/tools/rasm_src/Makefile b/tools/rasm_src/Makefile new file mode 100644 index 0000000..5d3ee4e --- /dev/null +++ b/tools/rasm_src/Makefile @@ -0,0 +1,11 @@ +all: rasm + +rasm: rasm_v0119.c + gcc -s -O2 $< -o $@ -lm -lrt -march=native + cp rasm .. + +clean: + rm -f rasm + +.PHONY: all clean + diff --git a/tools/rasm_src/decrunch/aplib_z80_todo.asm b/tools/rasm_src/decrunch/aplib_z80_todo.asm new file mode 100644 index 0000000..6843a14 --- /dev/null +++ b/tools/rasm_src/decrunch/aplib_z80_todo.asm @@ -0,0 +1,190 @@ +;Z80 Version by Dan Weiss +;Call depack. +;hl = source +;de = dest + +ap_bits: .db 0 +ap_byte: .db 0 +lwm: .db 0 +r0: .dw 0 + +ap_getbit: + push bc + ld bc,(ap_bits) + rrc c + jr nc,ap_getbit_continue + ld b,(hl) + inc hl +ap_getbit_continue: + ld a,c + and b + ld (ap_bits),bc + pop bc + ret + +ap_getbitbc: ;doubles BC and adds the read bit + sla c + rl b + call ap_getbit + ret z + inc bc + ret + +ap_getgamma: + ld bc,1 +ap_getgammaloop: + call ap_getbitbc + call ap_getbit + jr nz,ap_getgammaloop + ret + + +depack: + ;hl = source + ;de = dest + ldi + xor a + ld (lwm),a + inc a + ld (ap_bits),a + +aploop: + call ap_getbit + jp z, apbranch1 + call ap_getbit + jr z, apbranch2 + call ap_getbit + jr z, apbranch3 + ;LWM = 0 + xor a + ld (lwm),a + ;get an offset + ld bc,0 + call ap_getbitbc + call ap_getbitbc + call ap_getbitbc + call ap_getbitbc + ld a,b + or c + jr nz,apbranch4 + xor a ;write a 0 + ld (de),a + inc de + jr aploop +apbranch4: + ex de,hl ;write a previous bit (1-15 away from dest) + push hl + sbc hl,bc + ld a,(hl) + pop hl + ld (hl),a + inc hl + ex de,hl + jr aploop +apbranch3: + ;use 7 bit offset, length = 2 or 3 + ;if a zero is encountered here, it's EOF + ld c,(hl) + inc hl + rr c + ret z + ld b,2 + jr nc,ap_dont_inc_b + inc b +ap_dont_inc_b: + ;LWM = 1 + ld a,1 + ld (lwm),a + + push hl + ld a,b + ld b,0 + ;R0 = c + ld (r0),bc + ld h,d + ld l,e + or a + sbc hl,bc + ld c,a + ldir + pop hl + jr aploop +apbranch2: + ;use a gamma code * 256 for offset, another gamma code for length + call ap_getgamma + dec bc + dec bc + ld a,(lwm) + or a + jr nz,ap_not_lwm + ;bc = 2? + ld a,b + or c + jr nz,ap_not_zero_gamma + ;if gamma code is 2, use old r0 offset, and a new gamma code for length + call ap_getgamma + push hl + ld h,d + ld l,e + push bc + ld bc,(r0) + sbc hl,bc + pop bc + ldir + pop hl + jr ap_finishup + +ap_not_zero_gamma: + dec bc +ap_not_lwm: + ;do I even need this code? + ;bc=bc*256+(hl), lazy 16bit way + ld b,c + ld c,(hl) + inc hl + ld (r0),bc + push bc + call ap_getgamma + ex (sp),hl + ;bc = len, hl=offs + push de + ex de,hl + ;some comparison junk for some reason + ld hl,31999 + or a + sbc hl,de + jr nc,skip1 + inc bc +skip1: + ld hl,1279 + or a + sbc hl,de + jr nc,skip2 + inc bc +skip2: + ld hl,127 + or a + sbc hl,de + jr c,skip3 + inc bc + inc bc +skip3: + ;bc = len, de = offs, hl=junk + pop hl + push hl + or a + sbc hl,de + pop de + ;hl=dest-offs, bc=len, de = dest + ldir + pop hl +ap_finishup: + ld a,1 + ld (lwm),a + jp aploop + +apbranch1: + ldi + xor a + ld (lwm),a + jp aploop diff --git a/tools/rasm_src/decrunch/deexo.asm b/tools/rasm_src/decrunch/deexo.asm new file mode 100644 index 0000000..6a4a7ac --- /dev/null +++ b/tools/rasm_src/decrunch/deexo.asm @@ -0,0 +1,118 @@ +;Exomizer 2 Z80 decoder
+; by Metalbrain
+;
+; optimized by Antonio Villena and Urusergi (169 bytes)
+;
+; compression algorithm by Magnus Lind
+
+;input: hl=compressed data start
+; de=uncompressed destination start
+;
+; you may change exo_mapbasebits to point to any free buffer
+;
+;ATTENTION!
+;A huge speed boost (around 14%) can be gained at the cost of only 5 bytes.
+;If you want this, replace all instances of "call exo_getbit" with "srl a" followed by
+;"call z,exo_getbit", and remove the first two instructions in exo_getbit routine.
+
+Macro Mizoumizeur
+
+@deexo: ld iy, @exo_mapbasebits+11
+ ld a, (hl)
+ inc hl
+ ld b, 52
+ push de
+ cp a
+@exo_initbits: ld c, 16
+ jr nz, @exo_get4bits
+ ld ixl, c
+ ld de, 1 ;DE=b2
+@exo_get4bits: srl a: call z, @exo_getbit ;get one bit
+ rl c
+ jr nc, @exo_get4bits
+ inc c
+ push hl
+ ld hl, 1
+ ld (iy+41), c ;bits[i]=b1 (and opcode 41 == add hl,hl)
+@exo_setbit: dec c
+ jr nz, @exo_setbit-1 ;jump to add hl,hl instruction
+ ld (iy-11), e
+ ld (iy+93), d ;base[i]=b2
+ add hl, de
+ ex de, hl
+ inc iy
+ pop hl
+ dec ixl
+ djnz @exo_initbits
+ pop de
+ jr @exo_mainloop
+@exo_literalrun: ld e, c ;DE=1
+@exo_getbits: dec b
+ ret z
+@exo_getbits1: srl a : call z,@exo_getbit
+ rl e
+ rl d
+ jr nc, @exo_getbits
+ ld b, d
+ ld c, e
+ pop de
+@exo_literalcopy:ldir
+@exo_mainloop: inc c
+ srl a : call z,@exo_getbit ;literal?
+ jr c, @exo_literalcopy
+ ld c, 239
+@exo_getindex: srl a : call z,@exo_getbit
+ inc c
+ jr nc,@exo_getindex
+ ret z
+ push de
+ ld d, b
+ jp p, @exo_literalrun
+ ld iy, @exo_mapbasebits-229
+ call @exo_getpair
+ push de
+ rlc d
+ jr nz, @exo_dontgo
+ dec e
+ ld bc, 512+32 ;2 bits, 48 offset
+ jr z, @exo_goforit
+ dec e ;2?
+@exo_dontgo: ld bc, 1024+16 ;4 bits, 32 offset
+ jr z, @exo_goforit
+ ld de, 0
+ ld c, d ;16 offset
+@exo_goforit: call @exo_getbits1
+ ld iy, @exo_mapbasebits+27
+ add iy, de
+ call @exo_getpair
+ pop bc
+ ex (sp), hl
+ push hl
+ sbc hl, de
+ pop de
+ ldir
+ pop hl
+ jr @exo_mainloop ;Next!
+
+@exo_getpair: add iy, bc
+ ld e, d
+ ld b, (iy+41)
+ call @exo_getbits
+ ex de, hl
+ ld c, (iy-11)
+ ld b, (iy+93)
+ add hl, bc ;Always clear C flag
+ ex de, hl
+ ret
+
+@exo_getbit: ; srl a
+ ;ret nz
+ ld a, (hl)
+ inc hl
+ rra
+ ret
+
+@exo_mapbasebits: defs 156 ;tables for bits, baseL, baseH
+
+Mend
+
diff --git a/tools/rasm_src/decrunch/dzx7_turbo.asm b/tools/rasm_src/decrunch/dzx7_turbo.asm new file mode 100644 index 0000000..779ced5 --- /dev/null +++ b/tools/rasm_src/decrunch/dzx7_turbo.asm @@ -0,0 +1,80 @@ +; -----------------------------------------------------------------------------
+; ZX7 decoder by Einar Saukas & Urusergi
+; "Turbo" version (88 bytes, 25% faster)
+; -----------------------------------------------------------------------------
+; Parameters:
+; HL: source address (compressed data)
+; DE: destination address (decompressing)
+; -----------------------------------------------------------------------------
+
+dzx7_turbo:
+ ld a, $80
+dzx7t_copy_byte_loop:
+ ldi ; copy literal byte
+dzx7t_main_loop:
+ add a, a ; check next bit
+ call z, dzx7t_load_bits ; no more bits left?
+ jr nc, dzx7t_copy_byte_loop ; next bit indicates either literal or sequence
+
+; determine number of bits used for length (Elias gamma coding)
+ push de
+ ld bc, 1
+ ld d, b
+dzx7t_len_size_loop:
+ inc d
+ add a, a ; check next bit
+ call z, dzx7t_load_bits ; no more bits left?
+ jr nc, dzx7t_len_size_loop
+ jp dzx7t_len_value_start
+
+; determine length
+dzx7t_len_value_loop:
+ add a, a ; check next bit
+ call z, dzx7t_load_bits ; no more bits left?
+ rl c
+ rl b
+ jr c, dzx7t_exit ; check end marker
+dzx7t_len_value_start:
+ dec d
+ jr nz, dzx7t_len_value_loop
+ inc bc ; adjust length
+
+; determine offset
+ ld e, (hl) ; load offset flag (1 bit) + offset value (7 bits)
+ inc hl
+ defb $cb, $33 ; opcode for undocumented instruction "SLL E" aka "SLS E"
+ jr nc, dzx7t_offset_end ; if offset flag is set, load 4 extra bits
+ add a, a ; check next bit
+ call z, dzx7t_load_bits ; no more bits left?
+ rl d ; insert first bit into D
+ add a, a ; check next bit
+ call z, dzx7t_load_bits ; no more bits left?
+ rl d ; insert second bit into D
+ add a, a ; check next bit
+ call z, dzx7t_load_bits ; no more bits left?
+ rl d ; insert third bit into D
+ add a, a ; check next bit
+ call z, dzx7t_load_bits ; no more bits left?
+ ccf
+ jr c, dzx7t_offset_end
+ inc d ; equivalent to adding 128 to DE
+dzx7t_offset_end:
+ rr e ; insert inverted fourth bit into E
+
+; copy previous sequence
+ ex (sp), hl ; store source, restore destination
+ push hl ; store destination
+ sbc hl, de ; HL = destination - offset - 1
+ pop de ; DE = destination
+ ldir
+dzx7t_exit:
+ pop hl ; restore source address (compressed data)
+ jp nc, dzx7t_main_loop
+
+dzx7t_load_bits:
+ ld a, (hl) ; load another group of 8 bits
+ inc hl
+ rla
+ ret
+
+; -----------------------------------------------------------------------------
diff --git a/tools/rasm_src/decrunch/exomizer3megachur.asm b/tools/rasm_src/decrunch/exomizer3megachur.asm new file mode 100644 index 0000000..ea1973e --- /dev/null +++ b/tools/rasm_src/decrunch/exomizer3megachur.asm @@ -0,0 +1,210 @@ +;Exomizer 2 Z80 decoder
+;Copyright (C) 2008-2016 by Jaime Tejedor Gomez (Metalbrain)
+;
+;Optimized by Antonio Villena and Urusergi (169 bytes)
+;
+;Compression algorithm by Magnus Lind
+;
+; This depacker is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; This library is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public
+; License along with this library; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;
+;
+;input- hl=compressed data start
+; de=uncompressed destination start
+;
+; you may change exo_mapbasebits to point to any free buffer
+;
+;ATTENTION!
+;A huge speed boost (around 14%) can be gained at the cost of only 5 bytes.
+;If you want this, replace all instances of "call exo_getbit" with "srl a" followed by
+;"call z,exo_getbit", and remove the first two instructions in exo_getbit routine.
+; ---------------------------
+; modified by Megachur in 2018
+; ---------------------------
+; hl -> compressed data start
+; de -> uncompressed destination start
+; ---------------------------
+
+;EXO_BACKWARD equ 1
+ENABLE_MEXO_GETBIT equ 1
+
+list:EXOMIZER_ADDRESS:nolist
+; ---------------------------
+MACRO MEXO_GETBIT
+ srl a
+ jr nz,@1
+ ld a,(hl)
+ IFDEF EXO_BACKWARD
+ dec hl
+ ELSE
+ inc hl
+ ENDIF
+ rra
+@1
+ENDM
+
+deexo:
+ ld iy,exo_mapbasebits+11
+ ld a,(hl)
+
+ IFDEF EXO_BACKWARD
+ dec hl
+ ELSE
+ inc hl
+ ENDIF
+
+ ld b,52
+ push de
+ cp a
+
+exo_initbits:
+ ld c,16
+ jr nz,exo_get4bits
+ ld ixl,c
+ ld de,1 ;DE=b2
+
+exo_get4bits:
+ IFDEF ENABLE_MEXO_GETBIT
+ MEXO_GETBIT
+ ELSE
+ srl a:call z,exo_getbit ;call exo_getbit ;get one bit
+ ENDIF
+ rl c
+ jr nc,exo_get4bits
+ inc c
+ push hl
+ ld hl,1
+ ld (iy+41),c ;bits[i]=b1 (and opcode 41 == add hl,hl)
+
+exo_setbit:
+ dec c
+ jr nz,exo_setbit-1 ;jump to add hl,hl instruction
+ ld (iy-11),e
+ ld (iy+93),d ;base[i]=b2
+ add hl,de
+ ex de,hl
+ inc iy
+ pop hl
+ dec ixl
+ djnz exo_initbits
+ pop de
+ jr exo_mainloop
+
+exo_literalrun:
+ ld e,c ;DE=1
+
+exo_getbits:
+ dec b
+ ret z
+
+exo_getbits1:
+ IFDEF ENABLE_MEXO_GETBIT
+ MEXO_GETBIT
+ ELSE
+ srl a:call z,exo_getbit ;call exo_getbit
+ ENDIF
+ rl e
+ rl d
+ jr nc,exo_getbits
+ ld b,d
+ ld c,e
+ pop de
+
+exo_literalcopy:
+ IFDEF EXO_BACKWARD
+ lddr
+ ELSE
+ ldir
+ ENDIF
+exo_mainloop:
+ inc c
+ IFDEF ENABLE_MEXO_GETBIT
+ MEXO_GETBIT
+ ELSE
+ srl a:call z,exo_getbit ;call exo_getbit ;literal?
+ ENDIF
+ jr c,exo_literalcopy
+ ld c,239
+exo_getindex:
+ IFDEF ENABLE_MEXO_GETBIT
+ MEXO_GETBIT
+ ELSE
+ srl a:call z,exo_getbit ;call exo_getbit
+ ENDIF
+ inc c
+ jr nc,exo_getindex
+ ret z
+ push de
+ ld d,b
+ jp p,exo_literalrun
+ ld iy,exo_mapbasebits-229
+ call exo_getpair
+ push de
+ rlc d
+ jr nz,exo_dontgo
+ dec e
+ ld bc,512+32 ;2 bits,48 offset
+ jr z,exo_goforit
+ dec e ;2?
+exo_dontgo:
+ ld bc,1024+16 ;4 bits,32 offset
+ jr z,exo_goforit
+ ld de,0
+ ld c,d ;16 offset
+exo_goforit:
+ call exo_getbits1
+ ld iy,exo_mapbasebits+27
+ add iy,de
+ call exo_getpair
+ pop bc
+ ex (sp),hl
+ IFDEF EXO_BACKWARD
+ ex de,hl
+ add hl,de
+ lddr
+ ELSE
+ push hl
+ sbc hl,de
+ pop de
+ ldir
+ ENDIF
+ pop hl
+ jr exo_mainloop ;Next!
+exo_getpair:
+ add iy,bc
+ ld e,d
+ ld b,(iy+41)
+ call exo_getbits
+ ex de,hl
+ ld c,(iy-11)
+ ld b,(iy+93)
+ add hl,bc ;Always clear C flag
+ ex de,hl
+ ret
+
+ IFDEF ENABLE_MEXO_GETBIT
+ ELSE
+exo_getbit:
+; srl a
+; ret nz
+ ld a,(hl)
+ inc hl
+ rra
+ ret
+ ENDIF
+
+exo_mapbasebits:
+ ds 156,#00 ;tables for bits,baseL,baseH
+; ---------------------------
+list:EXOMIZER_ADDRESS_LENGTH equ $-EXOMIZER_ADDRESS:nolist
\ No newline at end of file diff --git a/tools/rasm_src/decrunch/lz48decrunch_v006.asm b/tools/rasm_src/decrunch/lz48decrunch_v006.asm new file mode 100644 index 0000000..750b571 --- /dev/null +++ b/tools/rasm_src/decrunch/lz48decrunch_v006.asm @@ -0,0 +1,113 @@ +;
+; LZ48 decrunch
+;
+; hl compressed data adress
+; de output adress of data
+;
+
+
+org #8000
+
+; CALL #8000,source,destination
+di
+
+; parameters
+ld h,(ix+3)
+ld l,(ix+2)
+ld d,(ix+1)
+ld e,(ix+0)
+
+call LZ48_decrunch
+
+ei
+ret
+
+
+
+
+
+LZ48_decrunch
+ldi
+ld b,0
+
+nextsequence
+ld a,(hl)
+inc hl
+ld lx,a
+and #F0
+jr z,lzunpack ; no litteral bytes
+rrca
+rrca
+rrca
+rrca
+
+ld c,a
+cp 15 ; more bytes for length?
+jr nz,copyliteral
+
+getadditionallength
+ld a,(hl)
+inc hl
+inc a
+jr nz,lengthnext
+inc b
+dec bc
+jr getadditionallength
+lengthnext
+dec a
+add a,c
+ld c,a
+ld a,b
+adc a,0
+ld b,a ; bc=length
+
+copyliteral
+ldir
+
+lzunpack
+ld a,lx
+and #F
+add 3
+ld c,a
+cp 18 ; more bytes for length?
+jr nz,readoffset
+
+getadditionallengthbis
+ld a,(hl)
+inc hl
+inc a
+jr nz,lengthnextbis
+inc b
+dec bc
+jr getadditionallengthbis
+lengthnextbis
+dec a
+add a,c
+ld c,a
+ld a,b
+adc a,0
+ld b,a ; bc=length
+
+readoffset
+; read encoded offset
+ld a,(hl)
+inc a
+ret z ; LZ48 end with zero offset
+inc hl
+push hl
+ld l,a
+ld a,e
+sub l
+ld l,a
+ld a,d
+sbc a,0
+ld h,a
+; source=dest-copyoffset
+
+copykey
+ldir
+
+pop hl
+jr nextsequence
+
+
diff --git a/tools/rasm_src/decrunch/lz49decrunch_v001.asm b/tools/rasm_src/decrunch/lz49decrunch_v001.asm new file mode 100644 index 0000000..7f811b5 --- /dev/null +++ b/tools/rasm_src/decrunch/lz49decrunch_v001.asm @@ -0,0 +1,138 @@ +;
+; LZ48 decrunch
+; input
+; hl compressed data adress
+; de output adress of data
+;
+; output
+; hl last adress of compressed data read (you must inc once for LZ48 stream)
+; de last adress of decrunched data write +1
+; bc always 3
+; a always zero
+; lx undetermined
+; flags (inc a -> 0)
+
+org #8000
+
+; CALL #8000,source,destination
+di
+
+; parameters
+ld h,(ix+3)
+ld l,(ix+2)
+ld d,(ix+1)
+ld e,(ix+0)
+
+call LZ49_decrunch
+
+ei
+ret
+
+
+
+
+
+LZ49_decrunch
+ldi
+ld b,0
+
+nextsequence
+ld a,(hl)
+inc hl
+ld lx,a
+and #70
+jr z,lzunpack ; no litteral bytes
+rrca
+rrca
+rrca
+rrca
+
+ld c,a
+cp 7 ; more bytes for length?
+jr nz,copyliteral
+
+getadditionallength
+ld a,(hl)
+inc hl
+inc a
+jr nz,lengthnext
+inc b
+dec bc
+jr getadditionallength
+lengthnext
+dec a
+add a,c
+ld c,a
+ld a,b
+adc a,0
+ld b,a ; bc=length
+
+copyliteral
+ldir
+
+lzunpack
+ld a,lx
+and #F
+add 3
+ld c,a
+cp 18 ; more bytes for length?
+jr nz,readoffset
+
+getadditionallengthbis
+ld a,(hl)
+inc hl
+inc a
+jr nz,lengthnextbis
+inc b
+dec bc
+jr getadditionallengthbis
+lengthnextbis
+dec a
+add a,c
+ld c,a
+ld a,b
+adc a,0
+ld b,a ; bc=length
+
+readoffset
+ld a,lx
+add a
+jr c,extendedoffset
+; read encoded offset
+ld a,(hl)
+inc a
+ret z ; LZ48 end with zero offset
+inc hl
+push hl
+ld l,a
+ld a,e
+sub l
+ld l,a
+ld a,d
+sbc a,0
+ld h,a
+; source=dest-copyoffset
+ldir
+pop hl
+jr nextsequence
+
+extendedoffset
+ld a,(hl)
+inc hl
+push hl
+inc a
+ld l,a
+ld a,e
+sub l
+ld l,a
+ld a,d
+sbc a,1
+ld h,a
+; source=dest-copyoffset
+ldir
+pop hl
+jr nextsequence
+
+
+
+
diff --git a/tools/rasm_src/decrunch/lz4_docent.asm b/tools/rasm_src/decrunch/lz4_docent.asm new file mode 100644 index 0000000..a0b2188 --- /dev/null +++ b/tools/rasm_src/decrunch/lz4_docent.asm @@ -0,0 +1,118 @@ +; decompress raw lz4 data packet +; on entry hl - start of packed buffer, de - destination buffer, bc - size of packed data +LZ4_decompress_raw: + push de ; store original destination pointer + push hl ; store start of compressed data source + add hl,bc ; calculate end address of compressed block + ld b,h ; move end address of compressed data to bc + ld c,l + pop hl ; restore start of compressed data source + push bc ; store end address of compessed data +; now hl - start of packed buffer, de - destination, bc - end of packed buffer + ld b,0 ; clear b, c is set later + +; get decompression token +LZ4_GetToken: + xor a ; reset c flag for sbc later + ld a,(hl) ; read token + inc hl + push af ; store token +; unpack 4 high bits to get the length of literal + rlca + rlca + rlca + rlca +; copy literals + and #f ; token can be max 15 - mask out unimportant bits + jr z,LZ4_skipcalc ; there is no literals, skip calculation of literal size + ld c,a ; set the count for calculation + cp #f ; if literal size <15 + jr nz, LZ4_copyliterals ; copy literal, else +; calculate total literal size by adding contents of following bytes + push de ; store destination + ex de,hl +; a = size of literal to copy, de=pointer to data to be added + ld h,0 ; set hl with size of literal to copy + ld l,a + +LZ4_calcloop: + ld a,(de) ; get additional literal size to add + inc de + ld c,a ; set bc to the length of literal + add hl,bc ; add it to the total literal length + cp #ff ; if literal=255 + jr z,LZ4_calcloop ; continue calculating the total literal size + ld b,h ; store total literal size to copy in bc + ld c,l + ex de,hl ; hl now contains current compressed data pointer + pop de ; restore destination to de + +LZ4_copyliterals: + ldir ; copy literal to destination + +LZ4_skipcalc: +; check for end of compressed data + pop af ; restore token, carry is cleared because of xor a at the beginning of GetToken + pop bc ; restore end address of compressed data + push hl ; store current compressed data pointer + sbc hl, bc ; check if we reached the end of compressed data buffer + pop hl ; restore current compressed data pointer + jr z,LZ4_decompress_success ; decompression finished + push bc ; store end address of compressed data + +; Copy Matches + and #f ; token can be max 15 - mask out unimportant bits. resets also c flag for sbc later +; get the offset + ld c,(hl) + inc hl + ld b,(hl) ; bc now contains the offset + inc hl + push hl ; store current compressed data pointer + push de ; store destination pointer + + ex de,hl + sbc hl,bc ; calculate from the offset the new decompressed data source to copy from +; hl contains new copy source, de source ptr + + ld b,0 ; load bc with the token + ld c,a + cp #f ; if matchlength <15 + jr nz, LZ4_copymatches ; copy matches. else + +; calculate total matchlength by adding additional bytes + push hl ; store current decompressed data source +; a = size of match to copy, de= pointer to data to be added + ld h,0 ; set hl with initial matchlength to copy + ld l,a +LZ4_calcloop2: + ld a,(de) ; get additional matchlength to add + inc de + ld c,a ; set bc to the matchlength + add hl,bc ; add it to the total match length + cp #ff ; if matchlength=255 + jr z,LZ4_calcloop2 ; continue calculating the total match length + ld b,h ; store total matchlength to copy in bc + ld c,l + pop hl ; restore current decompressed data source + pop af ; set stack to proper position by restoring destination pointer temporarily into af + ex de,hl + ex (sp),hl ; update current compressed data pointer on the stack to the new value from de + ex de,hl + push af ; restore stack + +LZ4_copymatches: + pop de ; restore destination pointer + inc bc ; add base length of 4 to get the correct size of matchlength + inc bc + inc bc + inc bc + ldir ; copy match + pop hl ; restore current compressed data source + jr LZ4_GetToken ; continue decompression +LZ4_decompress_success: + pop hl ; store destination pointer + sbc hl,de ; calculate the number of decompressed bytes + xor a ; clear exit code + ret + + diff --git a/tools/rasm_src/exomizer.h b/tools/rasm_src/exomizer.h new file mode 100644 index 0000000..1f3c7ca --- /dev/null +++ b/tools/rasm_src/exomizer.h @@ -0,0 +1,4942 @@ +/*
+
+Warning! This is a modified version of original sources!
+
+To sum up:
+- all include files and C sources were merged in a single file
+- existing logs were removed (except error logs)
+- main were removed and wrapper added
+
+
+*/
+
+#ifndef ALREADY_INCLUDED_CALLBACK
+#define ALREADY_INCLUDED_CALLBACK
+
+/*
+ * Copyright (c) 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+typedef int cb_cmp(const void *a, const void *b);
+typedef void cb_free(void *a);
+typedef void cb_fprint(FILE *f, const void *a);
+
+#endif
+#ifndef INCLUDED_INT
+#define INCLUDED_INT
+
+/*
+ * Copyright (c) 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+typedef signed char i8;
+typedef signed short int i16;
+typedef signed int i32;
+
+typedef unsigned char u8;
+typedef unsigned short int u16;
+typedef unsigned int u32;
+
+#endif
+#ifndef ALREADY_INCLUDED_PROGRESS
+#define ALREADY_INCLUDED_PROGRESS
+
+/*
+ * Copyright (c) 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+struct progress
+{
+ char *msg;
+ float factor;
+ int offset;
+ int last;
+};
+
+void progress_init(struct progress p[1], char *msg, int start, int end);
+
+void progress_bump(struct progress p[1], int pos);
+
+void progress_free(struct progress p[1]);
+
+#endif
+#ifndef ALREADY_INCLUDED_CHUNKPOOL
+#define ALREADY_INCLUDED_CHUNKPOOL
+
+/*
+ * Copyright (c) 2003 -2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+#define CHUNKPOOL_CHUNKS_MAX 64
+
+struct chunkpool {
+ int chunk_size;
+ int chunk;
+ int chunk_pos;
+ int chunk_max;
+ void *chunks[64];
+};
+
+void
+chunkpool_init(struct chunkpool *ctx, int size);
+
+void
+chunkpool_free(struct chunkpool *ctx);
+
+void chunkpool_free2(struct chunkpool *ctx, cb_free *f);
+
+void *
+chunkpool_malloc(struct chunkpool *ctx);
+
+void *
+chunkpool_calloc(struct chunkpool *ctx);
+
+#endif
+#ifndef ALREADY_INCLUDED_MATCH
+#define ALREADY_INCLUDED_MATCH
+/*
+ * Copyright (c) 2002 - 2005, 2013 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+struct match {
+ unsigned short int offset;
+ unsigned short int len;
+ struct match *next;
+};
+
+typedef struct match match[1];
+typedef struct match *matchp;
+typedef const struct match *const_matchp;
+
+struct pre_calc {
+ struct match_node *single;
+ const struct match *cache;
+};
+
+struct match_ctx {
+ struct chunkpool m_pool[1];
+ struct pre_calc (*info)[1];
+ unsigned short int *rle;
+ unsigned short int *rle_r;
+ const unsigned char *buf;
+ int len;
+ int max_offset;
+ int max_len;
+};
+
+typedef struct match_ctx match_ctx[1];
+typedef struct match_ctx *match_ctxp;
+
+//void match_ctx_init(match_ctx ctx, /* IN/OUT */ struct membuf *inbuf, /* IN */ int max_len, /* IN */ int max_offset, /* IN */ int use_imprecise_rle); /* IN */
+
+void match_ctx_free(match_ctx ctx); /* IN/OUT */
+
+/* this needs to be called with the indexes in
+ * reverse order */
+const_matchp matches_get(match_ctx ctx, /* IN/OUT */
+ int index); /* IN */
+
+void match_delete(match_ctx ctx, /* IN/OUT */
+ matchp mp); /* IN */
+
+struct matchp_cache_enum {
+ match_ctxp ctx;
+ const_matchp next;
+ match tmp1;
+ match tmp2;
+ int pos;
+};
+
+typedef struct matchp_cache_enum matchp_cache_enum[1];
+typedef struct matchp_cache_enum *matchp_cache_enump;
+
+void matchp_cache_get_enum(match_ctx ctx, /* IN */
+ matchp_cache_enum mpce); /* IN/OUT */
+
+typedef const_matchp matchp_enum_get_next_f(void *matchp_enum); /* IN/OUT */
+
+const_matchp matchp_cache_enum_get_next(void *matchp_cache_enum); /* IN */
+
+#endif
+#ifndef ALREADY_INCLUDED_OUTPUT
+#define ALREADY_INCLUDED_OUTPUT
+
+/*
+ * Copyright (c) 2002 - 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+struct _output_ctx {
+ unsigned int bitbuf;
+ int pos;
+ int start;
+ struct membuf *buf;
+};
+
+typedef struct _output_ctx output_ctx[1];
+typedef struct _output_ctx *output_ctxp;
+
+void output_ctx_init(output_ctx ctx, struct membuf *out); /* IN/OUT */
+
+unsigned int output_get_pos(output_ctx ctx); /* IN */
+
+void output_byte(output_ctx ctx, /* IN/OUT */
+ unsigned char byte); /* IN */
+
+void output_word(output_ctx ctx, /* IN/OUT */
+ unsigned short int word); /* IN */
+
+void output_bits_flush(output_ctx ctx); /* IN/OUT */
+
+void output_bits(output_ctx ctx, /* IN/OUT */
+ int count, /* IN */
+ int val); /* IN */
+
+void output_gamma_code(output_ctx ctx, /* IN/OUT */
+ int code); /* IN */
+#endif
+#ifndef ALREADY_INCLUDED_SEARCH
+#define ALREADY_INCLUDED_SEARCH
+
+/*
+ * Copyright (c) 2002 - 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+struct _search_node {
+ int index;
+ match match;
+ unsigned int total_offset;
+ float total_score;
+ struct _search_node *prev;
+};
+
+typedef struct _search_node search_node[1];
+typedef struct _search_node *search_nodep;
+typedef const struct _search_node *const_search_nodep;
+
+struct _encode_match_data {
+ output_ctxp out;
+ void *priv;
+};
+
+typedef struct _encode_match_data encode_match_data[1];
+typedef struct _encode_match_data *encode_match_datap;
+
+/* example of what may be used for priv data
+ * field in the encode_match_data struct */
+typedef
+float encode_int_f(int val, void *priv, output_ctxp out); /* IN */
+
+struct _encode_match_priv {
+ int lit_num;
+ int seq_num;
+ int rle_num;
+ float lit_bits;
+ float seq_bits;
+ float rle_bits;
+
+ encode_int_f *offset_f;
+ encode_int_f *len_f;
+ void *offset_f_priv;
+ void *len_f_priv;
+
+ output_ctxp out;
+};
+
+typedef struct _encode_match_priv encode_match_priv[1];
+typedef struct _encode_match_priv *encode_match_privp;
+/* end of example */
+
+typedef
+float encode_match_f(const_matchp mp, encode_match_data emd); /* IN */
+
+void search_node_dump(search_nodep snp); /* IN */
+
+void search_node_free(search_nodep snp); /* IN/OUT */
+
+search_nodep search_buffer(match_ctx ctx, /* IN */
+ encode_match_f * f, /* IN */
+ encode_match_data emd,
+ int use_literal_sequences); /* IN */
+
+struct _matchp_snp_enum {
+ const_search_nodep startp;
+ const_search_nodep currp;
+};
+
+typedef struct _matchp_snp_enum matchp_snp_enum[1];
+typedef struct _matchp_snp_enum *matchp_snp_enump;
+
+void matchp_snp_get_enum(const_search_nodep snp, /* IN */
+ matchp_snp_enum snpe); /* IN/OUT */
+
+const_matchp matchp_snp_enum_get_next(void *matchp_snp_enum);
+
+#endif
+#ifndef ALREADY_INCLUDED_RADIX
+#define ALREADY_INCLUDED_RADIX
+/*
+ * Copyright (c) 2002, 2003 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+typedef struct _radix_node *radix_nodep;
+
+struct _radix_root {
+ int depth;
+ radix_nodep root;
+ struct chunkpool mem[1];
+};
+
+typedef struct _radix_root radix_root[1];
+typedef struct _radix_root *radix_rootp;
+
+
+typedef void free_callback(void *data, void *priv);
+
+/* *f will be called even for null pointers */
+void radix_tree_free(radix_root rr, /* IN */
+ free_callback * f, /* IN */
+ void *priv); /* IN */
+
+void radix_tree_init(radix_root rr); /* IN */
+
+void radix_node_set(radix_root rr, /* IN */
+ unsigned int index, /* IN */
+ void *data); /* IN */
+
+void *radix_node_get(radix_root rr, /* IN */
+ unsigned int index); /* IN */
+
+#endif
+#ifndef MEMBUF_IO_ALREADY_INCLUDED
+#define MEMBUF_IO_ALREADY_INCLUDED
+
+/*
+ * Copyright (c) 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+void read_file(const char *name, struct membuf *buf);
+void write_file(const char *name, struct membuf *buf);
+
+#endif
+#ifndef ALREADY_INCLUDED_MEMBUF
+#define ALREADY_INCLUDED_MEMBUF
+
+/*
+ * Copyright (c) 2002 - 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+#define STATIC_MEMBUF_INIT {0, 0, 0}
+
+struct membuf {
+ void *buf;
+ int len;
+ int size;
+};
+
+void membuf_init(struct membuf *sb);
+void membuf_clear(struct membuf *sb);
+void membuf_free(struct membuf *sb);
+void membuf_new(struct membuf **sbp);
+void membuf_delete(struct membuf **sbp);
+/* Gets the length of data put into the membuf */
+int membuf_memlen(const struct membuf *sb);
+void membuf_truncate(struct membuf *sb, int len);
+
+/* returns the new len or < 0 if failure */
+int membuf_trim(struct membuf *sb, int pos);
+
+void *membuf_memcpy(struct membuf *sb, int offset, const void *mem, int len);
+void *membuf_append(struct membuf *sb, const void *mem, int len);
+void *membuf_append_char(struct membuf *sb, char c);
+void *membuf_insert(struct membuf *sb, int offset, const void *mem, int len);
+void membuf_remove(struct membuf *sb, int offset, int len);
+/* Grows the capacity if it's less than the given size */
+void membuf_atleast(struct membuf *sb, int size);
+/* Skrinks the capacity if it's greater than the given size */
+void membuf_atmost(struct membuf *sb, int size);
+/* Gets the current capacity of the membuf */
+int membuf_get_size(const struct membuf *sb);
+/* Gets a pointer to the internal buffer. Don't dereferece it beyond
+ * its size. */
+void *membuf_get(const struct membuf *sb);
+
+#endif
+#ifndef INCLUDED_PARSE
+#define INCLUDED_PARSE
+
+/*
+ * Copyright (c) 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+#define ATOM_TYPE_OP_ARG_NONE 0 /* uses u.op */
+#define ATOM_TYPE_OP_ARG_U8 1 /* uses u.op */
+#define ATOM_TYPE_OP_ARG_U16 2 /* uses u.op */
+#define ATOM_TYPE_OP_ARG_I8 3 /* uses u.op */
+#define ATOM_TYPE_OP_ARG_UI8 4 /* uses u.op */
+#define ATOM_TYPE_EXPRS 12 /* uses u.exprs */
+#define ATOM_TYPE_WORD_EXPRS 10 /* uses u.exprs */
+#define ATOM_TYPE_BYTE_EXPRS 11 /* uses u.exprs */
+#define ATOM_TYPE_RES 13 /* uses u.res */
+#define ATOM_TYPE_BUFFER 14 /* uses u.buffer */
+
+struct op
+{
+ struct expr *arg;
+ u8 code;
+};
+
+struct res
+{
+ struct expr *length;
+ struct expr *value;
+};
+
+struct buffer
+{
+ const char *name;
+ i32 length;
+ i32 skip;
+};
+
+struct atom
+{
+ u8 type;
+ union
+ {
+ struct op op;
+ struct vec *exprs;
+ struct buffer buffer;
+ struct res res;
+ } u;
+};
+
+extern int push_state_skip;
+extern int push_state_macro;
+extern int push_state_init;
+extern int num_lines;
+
+void parse_init(void);
+void parse_free(void);
+
+void set_initial_symbol(const char *symbol, i32 value);
+void initial_symbol_dump(int level, const char *symbol);
+
+struct membuf *new_initial_named_buffer(const char *name);
+
+int assemble(struct membuf *source, struct membuf *dest);
+
+/* start of internal functions */
+
+struct atom *new_op(u8 op_code, u8 op_size, struct expr *arg);
+struct atom *new_op0(u8 op_code);
+
+struct atom *new_exprs(struct expr *arg);
+struct atom *exprs_add(struct atom *atom, struct expr *arg);
+struct atom *exprs_to_byte_exprs(struct atom *atom);
+struct atom *exprs_to_word_exprs(struct atom *atom);
+
+struct atom *new_res(struct expr *len, struct expr *value);
+struct atom *new_incbin(const char *name,
+ struct expr *skip, struct expr *len);
+
+struct expr *new_is_defined(const char *symbol);
+struct expr *new_expr_inclen(const char *name);
+struct expr *new_expr_incword(const char *name,
+ struct expr *skip);
+
+void new_symbol_expr(const char *symbol, struct expr *arg);
+void new_symbol_expr_guess(const char *symbol, struct expr *arg);
+
+/* returns NULL if found, not otherwise, expp may be NULL. */
+const char *find_symref(const char *symbol,
+ struct expr **expp);
+
+int resolve_symbol(const char *symbol, int *has_valuep, i32 *valuep);
+void symbol_dump_resolved(int level, const char *symbol);
+
+void new_label(const char *label);
+void set_org(struct expr *arg);
+void push_if_state(struct expr *arg);
+void push_macro_state(const char *name);
+void macro_append(const char *text);
+void asm_error(const char *msg);
+void asm_echo(const char *msg, struct atom *atom);
+void asm_include(const char *msg);
+
+void output_atoms(struct membuf *out, struct vec *mem);
+void asm_src_buffer_push(struct membuf *buf);
+
+int assembleSinglePass(struct membuf *source, struct membuf *dest);
+
+#endif
+#ifndef ALREADY_INCLUDED_OPTIMAL
+#define ALREADY_INCLUDED_OPTIMAL
+
+/*
+ * Copyright (c) 2002 - 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+float optimal_encode(const_matchp mp, /* IN */
+ encode_match_data emp); /* IN */
+
+void optimal_init(encode_match_data emp); /* IN/OUT */
+
+void optimal_free(encode_match_data emd); /* IN */
+
+void optimal_optimize(encode_match_data emd, /* IN/OUT */
+ matchp_enum_get_next_f * f, /* IN */
+ void *priv); /* IN */
+
+void optimal_encoding_import(encode_match_data emd, /* IN/OUT */
+ const char *encoding); /* IN */
+
+const char *
+optimal_encoding_export(encode_match_data emd); /* IN */
+
+void optimal_dump(int level, encode_match_data emp); /* IN */
+
+void optimal_out(output_ctx out, /* IN/OUT */
+ encode_match_data emd); /* IN */
+
+#endif
+#ifndef ALREADY_INCLUDED_VEC
+#define ALREADY_INCLUDED_VEC
+
+/*
+ * Copyright (c) 2003 - 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+#define STATIC_VEC_INIT(EL_SIZE) {(EL_SIZE), STATIC_MEMBUF_INIT, 1}
+
+struct vec {
+ size_t elsize;
+ struct membuf buf;
+ int flags;
+};
+
+struct vec_iterator {
+ const struct vec *vec;
+ int pos;
+};
+
+void vec_init(struct vec *p, size_t elsize);
+void vec_clear(struct vec *p, cb_free * f);
+void vec_free(struct vec *p, cb_free * f);
+
+int vec_count(const struct vec *p);
+void *vec_get(const struct vec *p, int index);
+
+/**
+ * Returns a pointer to the set area or null if the index is out of
+ * bounds.
+ **/
+void *vec_set(struct vec *p, int index, const void *in);
+void *vec_insert(struct vec *p, int index, const void *in);
+void vec_remove(struct vec *p, int index);
+
+void *vec_push(struct vec *p, const void *in);
+
+/**
+ * Gets the position where the key is stored in the vector. The vector
+ * needs to be sorted for this function to work. Returns the position,
+ * -1 on error or a negative number that can be converted to where
+ * it should have been if it had been inserted. insert_pos = -(val + 2)
+ **/
+int vec_find(const struct vec *p, cb_cmp * f, const void *key);
+
+/**
+ * Gets a pointer to the element that the key points to.
+ * Returns a pointer that may be null if not found.
+ **/
+void *vec_find2(const struct vec *p, cb_cmp * f, const void *key);
+
+/**
+ * Inserts the in element in its correct position in a sorted vector.
+ * returns 1 if insertion is successful, 0 if element is already
+ * present or -1 on error. If out is not NULL it will be
+ * dereferenced and set to the inserted or present element.
+ **/
+int vec_insert_uniq(struct vec *p, cb_cmp * f, const void *in, void **out);
+void vec_sort(struct vec *p, cb_cmp * f);
+
+void vec_get_iterator(const struct vec *p, struct vec_iterator *i);
+void *vec_iterator_next(struct vec_iterator *i);
+
+int vec_equals(const struct vec *a, const struct vec *b, cb_cmp *equals);
+void vec_fprint(FILE *, const struct vec *a, cb_fprint *fprint);
+
+#endif
+#ifndef ALREADY_INCLUDED_MAP
+#define ALREADY_INCLUDED_MAP
+
+/*
+ * Copyright (c) 2006 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+struct map_entry {
+ const char *key;
+ void *value;
+};
+
+#define STATIC_MAP_INIT {STATIC_VEC_INIT(sizeof(struct map_entry))}
+
+struct map {
+ struct vec vec;
+};
+
+struct map_iterator {
+ struct vec_iterator vec;
+};
+
+void map_init(struct map *m);
+void map_clear(struct map *m);
+void map_free(struct map *m);
+
+void *map_put(struct map *m, const char *key, void *value);
+void *map_get(const struct map *m, const char *key);
+int map_contains_key(const struct map *m, const char *key);
+void map_put_all(struct map *m, const struct map *source);
+
+int map_contains(const struct map *m1, const struct map *m2, cb_cmp *f);
+
+/**
+ * If f is NULL, only the keys will be compared.
+ * returns -1 on error, 1 on equality and 0 otherwise,
+ **/
+int map_equals(const struct map *m1, const struct map *m2, cb_cmp *f);
+
+void map_get_iterator(const struct map *p, struct map_iterator *i);
+const struct map_entry *map_iterator_next(struct map_iterator *i);
+
+#endif
+#ifndef NAMED_BUFFER_INCLUDED
+#define NAMED_BUFFER_INCLUDED
+
+/*
+ * Copyright (c) 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+struct named_buffer {
+ struct map map;
+ struct chunkpool buf;
+};
+
+void named_buffer_init(struct named_buffer *nb);
+void named_buffer_free(struct named_buffer *nb);
+void named_buffer_clear(struct named_buffer *nb);
+
+void named_buffer_copy(struct named_buffer *nb,
+ const struct named_buffer *source);
+
+struct membuf *new_named_buffer(struct named_buffer *nb, const char *name);
+struct membuf *get_named_buffer(struct named_buffer *nb, const char *name);
+
+#endif
+#ifndef ALREADY_INCLUDED_LOG
+#define ALREADY_INCLUDED_LOG
+/*
+ * Copyright (c) 2002, 2003 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+
+#ifndef __GNUC__
+#define __attribute__(x) /*NOTHING*/
+#endif
+
+enum log_level {
+ LOG_MIN = -99,
+ LOG_FATAL = -40,
+ LOG_ERROR = -30,
+ LOG_WARNING = -20,
+ LOG_BRIEF = -10,
+ LOG_NORMAL = 0,
+ LOG_VERBOSE = 10,
+ LOG_TRACE = 20,
+ LOG_DEBUG = 30,
+ LOG_DUMP = 40,
+ LOG_MAX = 99
+};
+
+typedef
+void log_formatter_f(FILE * out, /* IN */
+ enum log_level level, /* IN */
+ const char *context, /* IN */
+ const char *); /* IN */
+
+/*
+ * this log output function adds nothing
+ */
+void raw_log_formatter(FILE * out, /* IN */
+ enum log_level level, /* IN */
+ const char *context, /* IN */
+ const char *log); /* IN */
+
+
+struct log_output;
+
+struct log_ctx;
+
+struct log_ctx *log_new(void);
+
+/* log_delete closes all added output streams
+ * and files except for stdout and stderr
+ */
+void log_delete(struct log_ctx *ctx);
+
+void log_set_level(struct log_ctx *ctx, /* IN/OUT */
+ enum log_level level); /* IN */
+
+void log_add_output_stream(struct log_ctx *ctx, /* IN/OUT */
+ enum log_level min, /* IN */
+ enum log_level max, /* IN */
+ log_formatter_f * default_f, /* IN */
+ FILE * out_stream); /* IN */
+
+void log_vlog(struct log_ctx *ctx, /* IN */
+ enum log_level level, /* IN */
+ const char *context, /* IN */
+ log_formatter_f * f, /* IN */
+ const char *printf_str, /* IN */
+ va_list argp);
+
+
+void log_log_default(const char *printf_str, /* IN */
+ ...)
+ __attribute__((format(printf,1,2)));
+
+/* some helper macros */
+
+extern struct log_ctx *G_log_ctx;
+extern enum log_level G_log_level;
+extern enum log_level G_log_log_level;
+
+#define LOG_SET_LEVEL(L) \
+do { \
+ log_set_level(G_log_ctx, (L)); \
+ G_log_level = (L); \
+} while(0)
+
+#define LOG_INIT(L) \
+do { \
+ G_log_ctx = log_new(); \
+ log_set_level(G_log_ctx, (L)); \
+ G_log_level = (L); \
+} while(0)
+
+#define LOG_INIT_CONSOLE(X) \
+do { \
+ G_log_ctx = log_new(); \
+ log_set_level(G_log_ctx, (X)); \
+ G_log_level = (X); \
+ log_add_output_stream(G_log_ctx, LOG_WARNING, LOG_MAX, NULL, stderr); \
+ log_add_output_stream(G_log_ctx, LOG_MIN, LOG_WARNING - 1, NULL, stderr); \
+} while(0)
+
+#define LOG_FREE log_delete(G_log_ctx)
+
+#define IS_LOGGABLE(L) (G_log_level >= (L))
+
+#define LOG(L, M) \
+do { \
+ if(IS_LOGGABLE(L)) { \
+ G_log_log_level = (L); \
+ log_log_default M; \
+ } \
+} while(0)
+
+
+void hex_dump(int level, unsigned char *p, int len);
+
+#endif
+#ifndef ALREADY_INCLUDED_GETFLAG
+#define ALREADY_INCLUDED_GETFLAG
+/*
+ * Copyright (c) 2002, 2003 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+extern int flagind;
+extern int flagflag;
+extern const char *flagarg;
+
+int getflag(int argc, char *argv[], const char *flags);
+
+#endif
+#ifndef ALREADY_INCLUDED_EXODEC
+#define ALREADY_INCLUDED_EXODEC
+
+/*
+ * Copyright (c) 2005 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+
+struct dec_table
+{
+ unsigned char table_bit[3];
+ unsigned char table_off[3];
+ unsigned char table_bi[100];
+ unsigned char table_lo[100];
+ unsigned char table_hi[100];
+};
+
+struct dec_ctx
+{
+ int inpos;
+ int inend;
+ unsigned char *inbuf;
+ struct membuf *outbuf;
+ unsigned int bitbuf;
+ /* dep_table */
+ struct dec_table t[1];
+ int bits_read;
+};
+
+/* returns the encoding */
+char *
+dec_ctx_init(struct dec_ctx ctx[1],
+ struct membuf *inbuf, struct membuf *outbuf);
+
+void
+dec_ctx_free(struct dec_ctx ctx[1]);
+
+void dec_ctx_decrunch(struct dec_ctx ctx[1]);
+
+#endif
+#ifndef EXO_UTIL_ALREADY_INCLUDED
+#define EXO_UTIL_ALREADY_INCLUDED
+
+/*
+ * Copyright (c) 2008 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+
+/*
+ * target is the basic token for the sys/call basic command
+ * it may be -1 for hardcoded detection of a few targets.
+ */
+int find_sys(const unsigned char *buf, int target);
+
+struct load_info
+{
+ int basic_txt_start; /* in */
+ int basic_var_start; /* out */
+ int run; /* out */
+ int start; /* out */
+ int end; /* out */
+};
+
+void load_located(char *filename, unsigned char mem[65536],
+ struct load_info *info);
+
+int str_to_int(const char *str, int *value);
+
+const char *fixup_appl(char *appl);
+
+#endif
+#ifndef EXO_HELPER_ALREADY_INCLUDED
+#define EXO_HELPER_ALREADY_INCLUDED
+
+/*
+ * Copyright (c) 2005, 2013 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+
+#define CRUNCH_OPTIONS_DEFAULT {NULL, 65535, 65535, 65535, 1, 0}
+
+struct common_flags
+{
+ struct crunch_options *options;
+ const char *outfile;
+};
+
+#define CRUNCH_FLAGS "cCe:m:M:p:o:qv"
+#define BASE_FLAGS "o:qv"
+
+void print_crunch_flags(enum log_level level, const char *default_outfile);
+
+void print_base_flags(enum log_level level, const char *default_outfile);
+
+typedef void print_usage_f(const char *appl, enum log_level level,
+ const char *default_outfile);
+
+void handle_crunch_flags(int flag_char, /* IN */
+ const char *flag_arg, /* IN */
+ print_usage_f *print_usage, /* IN */
+ const char *appl, /* IN */
+ struct common_flags *options); /* OUT */
+
+void handle_base_flags(int flag_char, /* IN */
+ const char *flag_arg, /* IN */
+ print_usage_f *print_usage, /* IN */
+ const char *appl, /* IN */
+ const char **default_outfilep); /* OUT */
+
+struct crunch_options
+{
+ const char *exported_encoding;
+ int max_passes;
+ int max_len;
+ int max_offset;
+ int use_literal_sequences;
+ int use_imprecise_rle;
+};
+
+struct crunch_info
+{
+ int literal_sequences_used;
+ int needed_safety_offset;
+};
+
+void print_license(void);
+
+void crunch_backwards(struct membuf *inbuf,
+ struct membuf *outbuf,
+ struct crunch_options *options, /* IN */
+ struct crunch_info *info); /* OUT */
+
+void exocrunch(struct membuf *inbuf,
+ struct membuf *outbuf,
+ struct crunch_options *options, /* IN */
+ struct crunch_info *info); /* OUT */
+
+void exodecrunch(int level,
+ struct membuf *inbuf,
+ struct membuf *outbuf);
+
+void decrunch_backwards(int level,
+ struct membuf *inbuf,
+ struct membuf *outbuf);
+
+void reverse_buffer(char *start, int len);
+#endif
+#ifndef ALREADY_INCLUDED_DESFX
+#define ALREADY_INCLUDED_DESFX
+
+/*
+ * Copyright (c) 2007 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+
+u16 decrunch_sfx(u8 mem[65536], u16 run, u16 *start, u16 *end);
+
+#endif
+
+/*
+ * Copyright (c) 2002 - 2007 Magnus Lind.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software, alter it and re-
+ * distribute it freely for any non-commercial, non-profit purpose subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any distribution.
+ *
+ * 4. The names of this software and/or it's copyright holders may not be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ */
+#define DEFAULT_OUTFILE "a.out"
+#define OUTPUT_FLAG_REVERSE 1
+
+/*
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+*/
+
+#ifdef WIN32
+#define vsnprintf _vsnprintf
+#endif
+#ifdef DJGPP
+#define vsnprintf(A, B, C, D) vsprintf((A),(C),(D))
+#endif
+
+#define BAR_LENGTH 64
+
+//extern struct membuf sfxdecr[];
+
+
+#define RADIX_TREE_NODE_RADIX 11U
+#define RADIX_TREE_NODE_MASK ((1U << RADIX_TREE_NODE_RADIX) - 1U)
+
+struct _radix_node {
+ struct _radix_node *rn;
+};
+
+void radix_tree_init(radix_root rr) /* IN */
+{
+ rr->depth = 0;
+ rr->root = NULL;
+
+ chunkpool_init(rr->mem, (1 << RADIX_TREE_NODE_RADIX) * sizeof(void *));
+}
+
+static
+void radix_tree_free_helper(int depth, radix_nodep rnp, free_callback * f, /* IN */
+ void *priv) /* IN */
+{
+ int i;
+ do
+ {
+ if (depth == 0)
+ {
+ /* do something to the data pointer? */
+ if (f != NULL)
+ {
+ f(rnp, priv);
+ }
+ break;
+ }
+ if (rnp == NULL)
+ {
+ /* tree not grown here */
+ break;
+ }
+
+ for (i = RADIX_TREE_NODE_MASK; i >= 0; --i)
+ {
+ radix_tree_free_helper(depth - 1, rnp[i].rn, f, priv);
+ rnp[i].rn = NULL;
+ }
+ }
+ while (0);
+}
+
+void radix_tree_free(radix_root rr, /* IN */
+ free_callback * f, /* IN */
+ void *priv) /* IN */
+{
+ radix_tree_free_helper(rr->depth, rr->root, f, priv);
+ rr->depth = 0;
+ rr->root = NULL;
+ chunkpool_free(rr->mem);
+}
+
+void radix_node_set(radix_rootp rrp, /* IN */
+ unsigned int index, /* IN */
+ void *data) /* IN */
+{
+ radix_nodep rnp;
+ radix_nodep *rnpp;
+ unsigned int mask;
+ int depth;
+
+ mask = ~0U << (RADIX_TREE_NODE_RADIX * rrp->depth);
+ while (index & mask)
+ {
+ /*LOG(LOG_DUMP, ("calloc called\n")); */
+ /* not deep enough, let's deepen the tree */
+ rnp = chunkpool_calloc(rrp->mem);
+
+ rnp[0].rn = rrp->root;
+ rrp->root = rnp;
+ rrp->depth += 1;
+
+ mask = ~0U << (RADIX_TREE_NODE_RADIX * rrp->depth);
+ }
+
+ /* go down */
+ rnpp = &rrp->root;
+ for (depth = rrp->depth - 1; depth >= 0; --depth)
+ {
+ unsigned int node_index;
+
+ if (*rnpp == NULL)
+ {
+ /*LOG(LOG_DUMP, ("calloc called\n")); */
+ /* tree is not grown in this interval */
+ *rnpp = chunkpool_calloc(rrp->mem);
+ }
+ node_index = ((index >> (RADIX_TREE_NODE_RADIX * depth)) &
+ RADIX_TREE_NODE_MASK);
+
+ rnpp = &((*rnpp)[node_index].rn);
+ }
+ *rnpp = data;
+}
+
+void *radix_node_get(radix_root rr, /* IN */
+ unsigned int index) /* IN */
+{
+ radix_nodep rnp;
+ unsigned short int depth;
+
+ /* go down */
+ rnp = rr->root;
+ for (depth = rr->depth - 1; depth < 0xffff; --depth)
+ {
+ unsigned short int node_index;
+
+ if (rnp == NULL)
+ {
+ /* tree is not grown in this interval */
+ break;
+ }
+ node_index = ((index >> (RADIX_TREE_NODE_RADIX * depth)) &
+ RADIX_TREE_NODE_MASK);
+
+ rnp = rnp[node_index].rn;
+ }
+ return rnp;
+}
+
+void search_node_free(search_nodep snp) /* IN */
+{
+ /* emty now since snp:s are stored in an array */
+}
+
+search_nodep search_buffer(match_ctx ctx, /* IN */
+ encode_match_f * f, /* IN */
+ encode_match_data emd, /* IN */
+ int use_literal_sequences)
+{
+ static struct membuf backing[1] = { STATIC_MEMBUF_INIT };
+ static search_node *snp_arr;
+ const_matchp mp = NULL;
+ search_nodep snp;
+ search_nodep best_copy_snp;
+ int best_copy_len;
+
+ search_nodep best_rle_snp;
+
+ int len = ctx->len + 1;
+
+
+ membuf_atleast(backing, len * sizeof(search_node));
+ snp_arr = membuf_get(backing);
+ memset(snp_arr, 0, len * sizeof(search_node));
+
+ --len;
+ snp = snp_arr[len];
+ snp->index = len;
+ snp->match->offset = 0;
+ snp->match->len = 0;
+ snp->total_offset = 0;
+ snp->total_score = 0;
+ snp->prev = NULL;
+
+ best_copy_snp = snp;
+ best_copy_len = 0.0;
+
+ best_rle_snp = NULL;
+
+ /* think twice about changing this code,
+ * it works the way it is. The last time
+ * I examined this code I was certain it was
+ * broken and broke it myself, trying to fix it. */
+ while (len > 0 && (mp = matches_get(ctx, len - 1)) != NULL)
+ {
+ float prev_score;
+ float prev_offset_sum;
+
+ if(use_literal_sequences)
+ {
+ /* check if we can do even better with copy */
+ snp = snp_arr[len];
+ if(best_copy_snp->total_score+best_copy_len * 8.0 -
+ snp->total_score > 0.0 || best_copy_len > 65535)
+ {
+ /* found a better copy endpoint */
+ best_copy_snp = snp;
+ best_copy_len = 0.0;
+ } else
+ {
+ float copy_score = best_copy_len * 8.0 + (1.0 + 17.0 + 17.0);
+ float total_copy_score = best_copy_snp->total_score +
+ copy_score;
+
+
+ if(snp->total_score > total_copy_score )
+ {
+ match local_mp;
+ /* here it is good to just copy instead of crunch */
+
+
+ local_mp->len = best_copy_len;
+ local_mp->offset = 0;
+ local_mp->next = NULL;
+ snp->total_score = total_copy_score;
+ snp->total_offset = best_copy_snp->total_offset;
+ snp->prev = best_copy_snp;
+ *snp->match = *local_mp;
+ }
+ }
+ /* end of copy optimization */
+ }
+
+ /* check if we can do rle */
+ snp = snp_arr[len];
+ if(best_rle_snp == NULL ||
+ snp->index + 65535 < best_rle_snp->index ||
+ snp->index + ctx->rle_r[snp->index] < best_rle_snp->index)
+ {
+ /* best_rle_snp can't be reached by rle from snp, reset it*/
+ if(ctx->rle[snp->index] > 0)
+ {
+ best_rle_snp = snp;
+ }
+ else
+ {
+ best_rle_snp = NULL;
+ }
+ }
+ else if(ctx->rle[snp->index] > 0 &&
+ snp->index + ctx->rle_r[snp->index] >= best_rle_snp->index)
+ {
+ float best_rle_score;
+ float total_best_rle_score;
+ float snp_rle_score;
+ float total_snp_rle_score;
+ match rle_mp;
+
+
+ /* snp and best_rle_snp is the same rle area,
+ * let's see which is best */
+#undef NEW_STYLE
+#ifdef NEW_STYLE
+ rle_mp->len = best_rle_snp->index - snp->index;
+#else
+ rle_mp->len = ctx->rle[best_rle_snp->index];
+#endif
+ rle_mp->offset = 1;
+ best_rle_score = f(rle_mp, emd);
+ total_best_rle_score = best_rle_snp->total_score +
+ best_rle_score;
+
+#ifdef NEW_STYLE
+ snp_rle_score = 0.0;
+#else
+ rle_mp->len = ctx->rle[snp->index];
+ rle_mp->offset = 1;
+ snp_rle_score = f(rle_mp, emd);
+#endif
+ total_snp_rle_score = snp->total_score + snp_rle_score;
+
+ if(total_snp_rle_score <= total_best_rle_score)
+ {
+ /* yes, the snp is a better rle than best_rle_snp */
+ best_rle_snp = snp;
+ }
+ }
+ if(best_rle_snp != NULL && best_rle_snp != snp)
+ {
+ float rle_score;
+ float total_rle_score;
+ /* check if rle is better */
+ match local_mp;
+ local_mp->len = best_rle_snp->index - snp->index;
+ local_mp->offset = 1;
+
+ rle_score = f(local_mp, emd);
+ total_rle_score = best_rle_snp->total_score + rle_score;
+
+ if(snp->total_score > total_rle_score)
+ {
+ /*here it is good to do rle instead of crunch */
+ snp->total_score = total_rle_score;
+ snp->total_offset = best_rle_snp->total_offset + 1;
+ snp->prev = best_rle_snp;
+
+ *snp->match = *local_mp;
+ }
+ }
+ /* end of rle optimization */
+
+
+ prev_score = snp_arr[len]->total_score;
+ prev_offset_sum = snp_arr[len]->total_offset;
+ while (mp != NULL)
+ {
+ matchp next;
+ int end_len;
+
+ match tmp;
+
+ next = mp->next;
+ end_len = 1;
+#if 0
+ if(next != NULL)
+ {
+ end_len = next->len + (next->offset > 0);
+ }
+#endif
+ *tmp = *mp;
+#if 1
+ tmp->next = NULL;
+#endif
+ for(tmp->len = mp->len; tmp->len >= end_len; --(tmp->len))
+ {
+ float score;
+ float total_score;
+ unsigned int total_offset;
+
+ score = f(tmp, emd);
+ total_score = prev_score + score;
+ total_offset = prev_offset_sum + tmp->offset;
+ snp = snp_arr[len - tmp->len];
+
+ if ((total_score < 100000000.0) &&
+ (snp->match->len == 0 ||
+ total_score < snp->total_score ||
+ (total_score == snp->total_score &&
+#if 1
+ (tmp->offset == 0 ||
+ (snp->match->len == tmp->len &&
+ (total_offset <= snp->total_offset))))))
+#endif
+ {
+ snp->index = len - tmp->len;
+
+ *snp->match = *tmp;
+ snp->total_offset = total_offset;
+ snp->total_score = total_score;
+ snp->prev = snp_arr[len];
+ }
+ //LOG(LOG_DUMP, ("\n"));
+ }
+ mp = next;
+ }
+
+ /* slow way to get to the next node for cur */
+ --len;
+ ++best_copy_len;
+ }
+ if(len > 0 && mp == NULL)
+ {
+ LOG(LOG_ERROR, ("No matches at len %d.\n", len));
+ }
+
+
+ return snp_arr[0];
+}
+
+void matchp_snp_get_enum(const_search_nodep snp, /* IN */
+ matchp_snp_enum snpe) /* IN/OUT */
+{
+ snpe->startp = snp;
+ snpe->currp = snp;
+}
+
+const_matchp matchp_snp_enum_get_next(void *matchp_snp_enum)
+{
+ matchp_snp_enump snpe;
+ const_matchp val;
+
+ snpe = matchp_snp_enum;
+
+ val = NULL;
+ while (snpe->currp != NULL && val == NULL)
+ {
+ val = snpe->currp->match;
+ snpe->currp = snpe->currp->prev;
+ }
+
+ if (snpe->currp == NULL)
+ {
+ snpe->currp = snpe->startp;
+ }
+ return val;
+}
+
+void
+chunkpool_init(struct chunkpool *ctx, int size)
+{
+ ctx->chunk_size = size;
+ ctx->chunk = -1;
+ ctx->chunk_max = (0x1fffff / size) * size;
+ ctx->chunk_pos = ctx->chunk_max;
+}
+
+void
+chunkpool_free2(struct chunkpool *ctx, cb_free *f)
+{
+ while(ctx->chunk >= 0)
+ {
+ if(f != NULL)
+ {
+ do
+ {
+ ctx->chunk_pos -= ctx->chunk_size;
+ f((char*)ctx->chunks[ctx->chunk] + ctx->chunk_pos);
+ }
+ while(ctx->chunk_pos > 0);
+ ctx->chunk_pos = ctx->chunk_max;
+ }
+ free(ctx->chunks[ctx->chunk]);
+ ctx->chunk -= 1;
+ }
+ ctx->chunk_size = -1;
+ ctx->chunk_max = -1;
+ ctx->chunk_pos = -1;
+}
+
+void
+chunkpool_free(struct chunkpool *ctx)
+{
+ chunkpool_free2(ctx, NULL);
+}
+
+void *
+chunkpool_malloc(struct chunkpool *ctx)
+{
+ void *p;
+ if(ctx->chunk_pos == ctx->chunk_max)
+ {
+ void *m;
+ if(ctx->chunk == CHUNKPOOL_CHUNKS_MAX - 1)
+ {
+ LOG(LOG_ERROR, ("out of chunks in file %s, line %d\n",
+ __FILE__, __LINE__));
+ LOG(LOG_BRIEF, ("chunk_size %d\n", ctx->chunk_size));
+ LOG(LOG_BRIEF, ("chunk_max %d\n", ctx->chunk_max));
+ LOG(LOG_BRIEF, ("chunk %d\n", ctx->chunk));
+ exit(-1);
+ }
+ m = malloc(ctx->chunk_max);
+ if (m == NULL)
+ {
+ LOG(LOG_ERROR, ("out of memory error in file %s, line %d\n",
+ __FILE__, __LINE__));
+ exit(-1);
+ }
+ ctx->chunk += 1;
+ ctx->chunks[ctx->chunk] = m;
+ ctx->chunk_pos = 0;
+ }
+ p = (char*)ctx->chunks[ctx->chunk] + ctx->chunk_pos;
+ ctx->chunk_pos += ctx->chunk_size;
+ return p;
+}
+
+void *
+chunkpool_calloc(struct chunkpool *ctx)
+{
+ void *p = chunkpool_malloc(ctx);
+ memset(p, 0, ctx->chunk_size);
+ return p;
+}
+
+static struct crunch_options default_options[1] = { CRUNCH_OPTIONS_DEFAULT };
+
+int do_output(match_ctx ctx,
+ search_nodep snp,
+ encode_match_data emd,
+ encode_match_f * f,
+ struct membuf *outbuf,
+ int *literal_sequences_used)
+{
+ int pos;
+ int pos_diff;
+ int max_diff;
+ int diff;
+ int copy_used = 0;
+ output_ctxp old;
+ output_ctx out;
+
+ output_ctx_init(out, outbuf);
+ old = emd->out;
+ emd->out = out;
+
+ pos = output_get_pos(out);
+
+ pos_diff = pos;
+ max_diff = 0;
+
+ output_gamma_code(out, 16);
+ output_bits(out, 1, 0); /* 1 bit out */
+
+ diff = output_get_pos(out) - pos_diff;
+ if(diff > max_diff)
+ {
+ max_diff = diff;
+ }
+
+ while (snp != NULL)
+ {
+ const_matchp mp;
+
+ mp = snp->match;
+ if (mp != NULL && mp->len > 0)
+ {
+ if (mp->offset == 0)
+ {
+ if(mp->len == 1)
+ {
+ /* literal */
+ output_byte(out, ctx->buf[snp->index]);
+ output_bits(out, 1, 1);
+ } else
+ {
+ int i;
+ for(i = 0; i < mp->len; ++i)
+ {
+ output_byte(out, ctx->buf[snp->index + i]);
+ }
+ output_bits(out, 16, mp->len);
+ output_gamma_code(out, 17);
+ output_bits(out, 1, 0);
+ copy_used = 1;
+ }
+ } else
+ {
+ f(mp, emd);
+ output_bits(out, 1, 0);
+ }
+
+ pos_diff += mp->len;
+ diff = output_get_pos(out) - pos_diff;
+ if(diff > max_diff)
+ {
+ max_diff = diff;
+ }
+ }
+ snp = snp->prev;
+ }
+
+ /* output header here */
+ optimal_out(out, emd);
+
+ output_bits_flush(out);
+
+ emd->out = old;
+
+ if(literal_sequences_used != NULL)
+ {
+ *literal_sequences_used = copy_used;
+ }
+
+ return max_diff;
+}
+
+search_nodep
+do_compress(match_ctx ctx, encode_match_data emd,
+ const char *exported_encoding,
+ int max_passes,
+ int use_literal_sequences)
+{
+ matchp_cache_enum mpce;
+ matchp_snp_enum snpe;
+ search_nodep snp;
+ search_nodep best_snp;
+ int pass;
+ float size;
+ float old_size;
+ char prev_enc[100];
+ const char *curr_enc;
+
+ pass = 1;
+ prev_enc[0] = '\0';
+
+ if(exported_encoding != NULL)
+ {
+ optimal_encoding_import(emd, exported_encoding);
+ }
+ else
+ {
+ matchp_cache_get_enum(ctx, mpce);
+ optimal_optimize(emd, matchp_cache_enum_get_next, mpce);
+ }
+
+ best_snp = NULL;
+ old_size = 100000000.0;
+
+ for (;;)
+ {
+ snp = search_buffer(ctx, optimal_encode, emd,
+ use_literal_sequences);
+ if (snp == NULL)
+ {
+ LOG(LOG_ERROR, ("error: search_buffer() returned NULL\n"));
+ exit(-1);
+ }
+
+ size = snp->total_score;
+
+ if (size >= old_size)
+ {
+ search_node_free(snp);
+ break;
+ }
+
+ if (best_snp != NULL)
+ {
+ search_node_free(best_snp);
+ }
+ best_snp = snp;
+ old_size = size;
+ ++pass;
+
+ if(pass > max_passes)
+ {
+ break;
+ }
+
+ optimal_free(emd);
+ optimal_init(emd);
+
+ matchp_snp_get_enum(snp, snpe);
+ optimal_optimize(emd, matchp_snp_enum_get_next, snpe);
+
+ curr_enc = optimal_encoding_export(emd);
+ if (strcmp(curr_enc, prev_enc) == 0)
+ {
+ break;
+ }
+ strcpy(prev_enc, curr_enc);
+ }
+
+ return best_snp;
+}
+
+void match_ctx_init(match_ctx ctx, /* IN/OUT */
+ struct membuf *inbuf, /* IN */
+ int max_len, /* IN */
+ int max_offset, /* IN */
+ int use_imprecise_rle); /* IN */
+void crunch_backwards(struct membuf *inbuf,
+ struct membuf *outbuf,
+ struct crunch_options *options, /* IN */
+ struct crunch_info *info) /* OUT */
+{
+ static match_ctx ctx;
+ encode_match_data emd;
+ search_nodep snp;
+ int outlen;
+ int safety;
+ int copy_used;
+
+ if(options == NULL)
+ {
+ options = default_options;
+ }
+
+ outlen = membuf_memlen(outbuf);
+ emd->out = NULL;
+ optimal_init(emd);
+
+ //LOG(LOG_NORMAL, (" Length of indata: %d bytes.\n", membuf_memlen(inbuf)));
+
+ match_ctx_init(ctx, inbuf, options->max_len, options->max_offset,
+ options->use_imprecise_rle);
+
+
+ emd->out = NULL;
+ optimal_init(emd);
+
+ snp = do_compress(ctx, emd, options->exported_encoding,
+ options->max_passes, options->use_literal_sequences);
+
+ safety = do_output(ctx, snp, emd, optimal_encode, outbuf, ©_used);
+ //LOG(LOG_NORMAL, (" Length of crunched data: %d bytes.\n",membuf_memlen(outbuf) - outlen));
+
+ optimal_free(emd);
+ search_node_free(snp);
+ match_ctx_free(ctx);
+
+ if(info != NULL)
+ {
+ info->literal_sequences_used = copy_used;
+ info->needed_safety_offset = safety;
+ }
+}
+
+void reverse_buffer(char *start, int len)
+{
+ char *end = start + len - 1;
+ char tmp;
+
+ while (start < end)
+ {
+ tmp = *start;
+ *start = *end;
+ *end = tmp;
+
+ ++start;
+ --end;
+ }
+}
+
+void exocrunch(struct membuf *inbuf,
+ struct membuf *outbuf,
+ struct crunch_options *options, /* IN */
+ struct crunch_info *info) /* OUT */
+{
+ int outpos;
+ reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf));
+ outpos = membuf_memlen(outbuf);
+
+ crunch_backwards(inbuf, outbuf, options, info);
+
+ reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf));
+ reverse_buffer((char*)membuf_get(outbuf) + outpos,
+ membuf_memlen(outbuf) - outpos);
+}
+
+void exodecrunch(int level,
+ struct membuf *inbuf,
+ struct membuf *outbuf)
+{
+ struct dec_ctx ctx[1];
+ char *enc;
+ enc = dec_ctx_init(ctx, inbuf, outbuf);
+
+ LOG(level, (" Encoding: %s\n", enc));
+
+ dec_ctx_decrunch(ctx);
+ dec_ctx_free(ctx);
+}
+
+void decrunch_backwards(int level,
+ struct membuf *inbuf,
+ struct membuf *outbuf)
+{
+ int outpos;
+ reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf));
+ outpos = membuf_memlen(outbuf);
+
+ exodecrunch(level, inbuf, outbuf);
+
+ reverse_buffer(membuf_get(inbuf), membuf_memlen(inbuf));
+ reverse_buffer((char*)membuf_get(outbuf) + outpos,
+ membuf_memlen(outbuf) - outpos);
+}
+
+void print_license(void)
+{
+}
+
+void print_base_flags(enum log_level level, const char *default_outfile)
+{
+ LOG(level,
+ (" -o <outfile> sets the outfile name, default is \"%s\"\n",
+ default_outfile));
+ LOG(level,
+ (" -q quiet mode, disables display output\n"
+ " -v displays version and the usage license\n"
+ " -- treats all following arguments as non-options\n"
+ " -? displays this help screen\n"));
+}
+
+void print_crunch_flags(enum log_level level, const char *default_outfile)
+{
+ LOG(level,
+ (" -c compatibility mode, disables the use of literal sequences\n"
+ " -C enable imprecise rle matching, trades result for speed\n"
+ " -e <encoding> uses the given encoding for crunching\n"
+ " -m <offset> sets the maximum sequence offset, default is 65535\n"
+ " -M <length> sets the maximum sequence length, default is 65535\n"
+ " -p <passes> limits the number of optimization passes, default is 65535\n"));
+ print_base_flags(level, default_outfile);
+}
+
+void handle_base_flags(int flag_char, /* IN */
+ const char *flag_arg, /* IN */
+ print_usage_f *print_usage, /* IN */
+ const char *appl, /* IN */
+ const char **default_outfilep) /* IN */
+{
+ switch(flag_char)
+ {
+ case 'o':
+ *default_outfilep = flag_arg;
+ break;
+ case 'q':
+ LOG_SET_LEVEL(LOG_BRIEF);
+ break;
+ case 'v':
+ print_license();
+ exit(0);
+ default:
+ if (flagflag != '?')
+ {
+ LOG(LOG_ERROR,
+ ("error, invalid option \"-%c\"", flagflag));
+ if (flagarg != NULL)
+ {
+ LOG(LOG_ERROR, (" with argument \"%s\"", flagarg));
+ }
+ LOG(LOG_ERROR, ("\n"));
+ }
+ print_usage(appl, LOG_BRIEF, *default_outfilep);
+ exit(0);
+ }
+}
+
+void handle_crunch_flags(int flag_char, /* IN */
+ const char *flag_arg, /* IN */
+ print_usage_f *print_usage, /* IN */
+ const char *appl, /* IN */
+ struct common_flags *flags) /* OUT */
+{
+ struct crunch_options *options = flags->options;
+ switch(flag_char)
+ {
+ case 'c':
+ options->use_literal_sequences = 0;
+ break;
+ case 'C':
+ options->use_imprecise_rle = 1;
+ break;
+ case 'e':
+ options->exported_encoding = flag_arg;
+ break;
+ case 'm':
+ if (str_to_int(flag_arg, &options->max_offset) != 0 ||
+ options->max_offset < 0 || options->max_offset >= 65536)
+ {
+ LOG(LOG_ERROR,
+ ("Error: invalid offset for -m option, "
+ "must be in the range of [0 - 65535]\n"));
+ print_usage(appl, LOG_NORMAL, flags->outfile);
+ exit(-1);
+ }
+ break;
+ case 'M':
+ if (str_to_int(flag_arg, &options->max_len) != 0 ||
+ options->max_len < 0 || options->max_len >= 65536)
+ {
+ LOG(LOG_ERROR,
+ ("Error: invalid offset for -n option, "
+ "must be in the range of [0 - 65535]\n"));
+ print_usage(appl, LOG_NORMAL, flags->outfile);
+ exit(-1);
+ }
+ break;
+ case 'p':
+ if (str_to_int(flag_arg, &options->max_passes) != 0 ||
+ options->max_passes < 1 || options->max_passes >= 65536)
+ {
+ LOG(LOG_ERROR,
+ ("Error: invalid value for -p option, "
+ "must be in the range of [1 - 65535]\n"));
+ print_usage(appl, LOG_NORMAL, flags->outfile);
+ exit(-1);
+ }
+ break;
+ default:
+ handle_base_flags(flag_char, flag_arg, print_usage,
+ appl, &flags->outfile);
+ }
+}
+
+int find_sys(const unsigned char *buf, int target)
+{
+ int outstart = -1;
+ int state = 1;
+ int i = 0;
+ /* skip link and line number */
+ buf += 4;
+ /* exit loop at line end */
+ while(i < 1000 && buf[i] != '\0')
+ {
+ unsigned char *sys_end;
+ int c = buf[i];
+ switch(state)
+ {
+ /* look for and consume sys token */
+ case 1:
+ if((target == -1 &&
+ (c == 0x9e /* cbm */ ||
+ c == 0x8c /* apple 2*/ ||
+ c == 0xbf /* oric 1*/)) ||
+ c == target)
+ {
+ state = 2;
+ }
+ break;
+ /* skip spaces and left parenthesis, if any */
+ case 2:
+ if(strchr(" (", c) != NULL) break;
+ state = 3;
+ /* convert string number to int */
+ case 3:
+ outstart = strtol((char*)(buf + i), (void*)&sys_end, 10);
+ if((buf + i) == sys_end)
+ {
+ /* we got nothing */
+ outstart = -1;
+ }
+ state = 4;
+ break;
+ case 4:
+ break;
+ }
+ ++i;
+ }
+
+ return outstart;
+}
+
+static int ExoUtil_get_byte(FILE *in)
+{
+ int byte = fgetc(in);
+ if(byte == EOF)
+ {
+ LOG(LOG_ERROR, ("Error: unexpected end of xex-file."));
+ fclose(in);
+ exit(-1);
+ }
+ return byte;
+}
+
+static int get_le_word(FILE *in)
+{
+ int word = ExoUtil_get_byte(in);
+ word |= ExoUtil_get_byte(in) << 8;
+ return word;
+}
+
+static int get_be_word(FILE *in)
+{
+ int word = ExoUtil_get_byte(in) << 8;
+ word |= ExoUtil_get_byte(in);
+ return word;
+}
+
+static
+FILE *
+open_file(char *name, int *load_addr)
+{
+ FILE * in;
+ int is_plain = 0;
+ int is_relocated = 0;
+ int load = -3;
+
+ do
+ {
+ char *load_str;
+ char *at_str;
+
+ in = fopen(name, "rb");
+ if (in != NULL)
+ {
+ /* We have succeded in opening the file.
+ * There's no address suffix. */
+ break;
+ }
+
+ /* hmm, let's see if the user is trying to relocate it */
+ load_str = strrchr(name, ',');
+ at_str = strrchr(name, '@');
+ if(at_str != NULL && (load_str == NULL || at_str > load_str))
+ {
+ is_plain = 1;
+ load_str = at_str;
+ }
+
+ if (load_str == NULL)
+ {
+ /* nope, */
+ break;
+ }
+
+ *load_str = '\0';
+ ++load_str;
+ is_relocated = 1;
+
+ /* relocation was requested */
+ if (str_to_int(load_str, &load) != 0)
+ {
+ /* we fail */
+ LOG(LOG_ERROR,
+ (" can't parse load address from \"%s\"\n", load_str));
+ exit(-1);
+ }
+
+ in = fopen(name, "rb");
+
+ } while (0);
+ if (in == NULL)
+ {
+ LOG(LOG_ERROR,
+ (" can't open file \"%s\" for input\n", name));
+ exit(-1);
+ }
+
+ if(!is_plain)
+ {
+ /* read the prg load address */
+ int prg_load = get_le_word(in);
+ if(!is_relocated)
+ {
+ load = prg_load;
+ /* unrelocated prg loading to $ffff is xex */
+ if(prg_load == 0xffff)
+ {
+ /* differentiate this from relocated $ffff files so it is
+ * possible to override the xex auto-detection. */
+ load = -1;
+ }
+ /* unrelocated prg loading to $1616 is Oric tap */
+ else if(prg_load == 0x1616)
+ {
+ load = -2;
+ }
+ }
+ }
+
+ if(load_addr != NULL)
+ {
+ *load_addr = load;
+ }
+ return in;
+}
+
+static void load_xex(unsigned char mem[65536], FILE *in,
+ struct load_info *info)
+{
+ int run = -1;
+ int jsr = -1;
+ int min = 65536, max = 0;
+
+ goto initial_state;
+ for(;;)
+ {
+ int start, end, len;
+
+ start = fgetc(in);
+ if(start == EOF) break;
+ ungetc(start, in);
+
+ start = get_le_word(in);
+ if(start == 0xffff)
+ {
+ /* allowed optional header */
+ initial_state:
+ start = get_le_word(in);
+ }
+ end = get_le_word(in);
+ if(start > 0xffff || end > 0xffff || end < start)
+ {
+ LOG(LOG_ERROR, ("Error: corrupt data in xex-file."));
+ fclose(in);
+ exit(-1);
+ }
+ if(start == 0x2e2 && end == 0x2e3)
+ {
+ /* init vector */
+ jsr = get_le_word(in);
+ LOG(LOG_VERBOSE, ("Found xex initad $%04X.\n", jsr));
+ continue;
+ }
+ if(start == 0x2e0 && end == 0x2e1)
+ {
+ /* run vector */
+ run = get_le_word(in);
+ LOG(LOG_VERBOSE, ("Found xex runad $%04X.\n", run));
+ continue;
+ }
+ ++end;
+ jsr = -1;
+ if(start < min) min = start;
+ if(end > max) max = end;
+
+ len = fread(mem + start, 1, end - start, in);
+ if(len != end - start)
+ {
+ LOG(LOG_ERROR, ("Error: unexpected end of xex-file.\n"));
+ fclose(in);
+ exit(-1);
+ }
+ LOG(LOG_VERBOSE, (" xex chunk loading from $%04X to $%04X\n",
+ start, end));
+ }
+
+ if(run == -1 && jsr != -1) run = jsr;
+
+ info->start = min;
+ info->end = max;
+ info->basic_var_start = -1;
+ info->run = -1;
+ if(run != -1)
+ {
+ info->run = run;
+ }
+}
+
+static void load_oric_tap(unsigned char mem[65536], FILE *in,
+ struct load_info *info)
+{
+ int c;
+ int autostart;
+ int start, end, len;
+
+ /* read oric tap header */
+
+ /* next byte must be 0x16 as we have already read two and must
+ * have at least three */
+ if(ExoUtil_get_byte(in) != 0x16)
+ {
+ LOG(LOG_ERROR, ("Error: fewer than three lead-in bytes ($16) "
+ "in Oric tap-file header.\n"));
+ fclose(in);
+ exit(-1);
+ }
+ /* optionally more 0x16 bytes */
+ while((c = ExoUtil_get_byte(in)) == 0x16);
+ /* next byte must be 0x24 */
+ if(c != 0x24)
+ {
+ LOG(LOG_ERROR, ("Error: bad sync byte after lead-in in Oric tap-file "
+ "header, got $%02X but expected $24\n", c));
+ fclose(in);
+ exit(-1);
+ }
+
+ /* now we are in sync, lets be lenient */
+ ExoUtil_get_byte(in); /* should be 0x0 */
+ ExoUtil_get_byte(in); /* should be 0x0 */
+ ExoUtil_get_byte(in); /* should be 0x0 or 0x80 */
+ autostart = (ExoUtil_get_byte(in) != 0); /* should be 0x0, 0x80 or 0xc7 */
+ end = get_be_word(in) + 1; /* the header end address is inclusive */
+ start = get_be_word(in);
+ ExoUtil_get_byte(in); /* should be 0x0 */
+ /* read optional file name */
+ while(ExoUtil_get_byte(in) != 0x0);
+
+ /* read the data */
+ len = fread(mem + start, 1, end - start, in);
+ if(len != end - start)
+ {
+ LOG(LOG_BRIEF, ("Warning: Oric tap-file contains %d byte(s) data "
+ "less than expected.\n", end - start - len));
+ end = start + len;
+ }
+ LOG(LOG_VERBOSE, (" Oric tap-file loading from $%04X to $%04X\n",
+ start, end));
+
+ /* fill in the fields */
+ info->start = start;
+ info->end = end;
+ info->run = -1;
+ info->basic_var_start = -1;
+ if(autostart)
+ {
+ info->run = start;
+ }
+ if(info->basic_txt_start >= start &&
+ info->basic_txt_start < end)
+ {
+ info->basic_var_start = end - 1;
+ }
+}
+
+static void load_prg(unsigned char mem[65536], FILE *in,
+ struct load_info *info)
+{
+ int len;
+ len = fread(mem + info->start, 1, 65536 - info->start, in);
+
+ info->end = info->start + len;
+ info->basic_var_start = -1;
+ info->run = -1;
+ if(info->basic_txt_start >= info->start &&
+ info->basic_txt_start < info->end)
+ {
+ info->basic_var_start = info->end;
+ }
+}
+
+void load_located(char *filename, unsigned char mem[65536],
+ struct load_info *info)
+{
+ int load;
+ FILE *in;
+
+ in = open_file(filename, &load);
+ if(load == -1)
+ {
+ /* file is an xex file */
+ load_xex(mem, in, info);
+ }
+ else if(load == -2)
+ {
+ /* file is an oric tap file */
+ load_oric_tap(mem, in, info);
+ }
+ else
+ {
+ /* file is a located plain file or a prg file */
+ info->start = load;
+ load_prg(mem, in, info);
+ }
+ fclose(in);
+
+ LOG(LOG_NORMAL,
+ (" filename: \"%s\", loading from $%04X to $%04X\n",
+ filename, info->start, info->end));
+}
+
+/* returns 0 if ok, 1 otherwise */
+int str_to_int(const char *str, int *value)
+{
+ int status = 0;
+ do {
+ char *str_end;
+ long lval;
+
+ /* base 0 is auto detect */
+ int base = 0;
+
+ if (*str == '\0')
+ {
+ /* no string to parse */
+ status = 1;
+ break;
+ }
+
+ if (*str == '$')
+ {
+ /* a $ prefix specifies base 16 */
+ ++str;
+ base = 16;
+ }
+
+ lval = strtol(str, &str_end, base);
+
+ if(*str_end != '\0')
+ {
+ /* there is garbage in the string */
+ status = 1;
+ break;
+ }
+
+ if(value != NULL)
+ {
+ /* all is well, set the out parameter */
+ *value = (int)lval;
+ }
+ } while(0);
+
+ return status;
+}
+
+const char *fixup_appl(char *appl)
+{
+ char *applp;
+
+ /* strip pathprefix from appl */
+ applp = strrchr(appl, '\\');
+ if (applp != NULL)
+ {
+ appl = applp + 1;
+ }
+ applp = strrchr(appl, '/');
+ if (applp != NULL)
+ {
+ appl = applp + 1;
+ }
+ /* strip possible exe suffix */
+ applp = appl + strlen(appl) - 4;
+ if(strcmp(applp, ".exe") == 0 || strcmp(applp, ".EXE") == 0)
+ {
+ *applp = '\0';
+ }
+ return appl;
+}
+
+char *get(struct membuf *buf)
+{
+ return membuf_get(buf);
+}
+
+int get_byte(struct dec_ctx *ctx)
+{
+ int c;
+ if(ctx->inpos == ctx->inend)
+ {
+ LOG(LOG_ERROR, ("unexpected end of input data\n"));
+ exit(-1);
+ }
+ c = ctx->inbuf[ctx->inpos++];
+
+ return c;
+}
+
+int
+get_bits(struct dec_ctx *ctx, int count)
+{
+ int val;
+
+ val = 0;
+
+ /*printf("get_bits: count = %d", count);*/
+ while(count-- > 0) {
+ if((ctx->bitbuf & 0x1FF) == 1) {
+ ctx->bitbuf = get_byte(ctx) | 0x100;
+ }
+ val <<= 1;
+ val |= ctx->bitbuf & 0x1;
+ ctx->bitbuf >>= 1;
+ /*printf("bit read %d\n", val &1);*/
+ ctx->bits_read++;
+ }
+ /*printf(" val = %d\n", val);*/
+ return val;
+}
+
+int
+get_gamma_code(struct dec_ctx *ctx)
+{
+ int gamma_code;
+ /* get bitnum index */
+ gamma_code = 0;
+ while(get_bits(ctx, 1) == 0)
+ {
+ ++gamma_code;
+ }
+ return gamma_code;
+}
+
+int
+get_cooked_code_phase2(struct dec_ctx *ctx, int index)
+{
+ int base;
+ struct dec_table *tp;
+ tp = ctx->t;
+
+ base = tp->table_lo[index] | (tp->table_hi[index] << 8);
+ return base + get_bits(ctx, tp->table_bi[index]);
+}
+
+static
+void
+table_init(struct dec_ctx *ctx, struct dec_table *tp) /* IN/OUT */
+{
+ int i;
+ unsigned int a = 0;
+ unsigned int b = 0;
+
+ tp->table_bit[0] = 2;
+ tp->table_bit[1] = 4;
+ tp->table_bit[2] = 4;
+
+ tp->table_off[0] = 48;
+ tp->table_off[1] = 32;
+ tp->table_off[2] = 16;
+
+ for(i = 0; i < 52; ++i)
+ {
+ if(i & 0xF)
+ {
+ a += 1 << b;
+ } else
+ {
+ a = 1;
+ }
+
+ tp->table_lo[i] = a & 0xFF;
+ tp->table_hi[i] = a >> 8;
+
+ b = get_bits(ctx, 4);
+
+ tp->table_bi[i] = b;
+
+ }
+}
+
+char *
+table_dump(struct dec_table *tp)
+{
+ int i, j;
+ static char buf[100];
+ char *p = buf;
+
+ for(i = 0; i < 16; ++i)
+ {
+ p += sprintf(p, "%X", tp->table_bi[i]);
+ }
+ for(j = 0; j < 3; ++j)
+ {
+ int start;
+ int end;
+ p += sprintf(p, ",");
+ start = tp->table_off[j];
+ end = start + (1 << tp->table_bit[j]);
+ for(i = start; i < end; ++i)
+ {
+ p += sprintf(p, "%X", tp->table_bi[i]);
+ }
+ }
+ return buf;
+}
+
+char *
+dec_ctx_init(struct dec_ctx *ctx, struct membuf *inbuf, struct membuf *outbuf)
+{
+ char *encoding;
+ ctx->bits_read = 0;
+
+ ctx->inbuf = membuf_get(inbuf);
+ ctx->inend = membuf_memlen(inbuf);
+ ctx->inpos = 0;
+
+ ctx->outbuf = outbuf;
+
+ /* init bitbuf */
+ ctx->bitbuf = get_byte(ctx);
+
+ /* init tables */
+ table_init(ctx, ctx->t);
+ encoding = table_dump(ctx->t);
+ return encoding;
+}
+
+void dec_ctx_free(struct dec_ctx *ctx)
+{
+}
+
+void dec_ctx_decrunch(struct dec_ctx ctx[1])
+{
+ int bits;
+ int val;
+ int i;
+ int len;
+ int offset;
+ int src = 0;
+
+ for(;;)
+ {
+ int literal = 0;
+ bits = ctx->bits_read;
+ if(get_bits(ctx, 1))
+ {
+ /* literal */
+ len = 1;
+
+ literal = 1;
+ goto literal;
+ }
+
+ val = get_gamma_code(ctx);
+ if(val == 16)
+ {
+ /* done */
+ break;
+ }
+ if(val == 17)
+ {
+ len = get_bits(ctx, 16);
+ literal = 1;
+
+ goto literal;
+ }
+
+ len = get_cooked_code_phase2(ctx, val);
+
+ i = (len > 3 ? 3 : len) - 1;
+
+ val = ctx->t->table_off[i] + get_bits(ctx, ctx->t->table_bit[i]);
+ offset = get_cooked_code_phase2(ctx, val);
+
+ src = membuf_memlen(ctx->outbuf) - offset;
+
+ literal:
+ do {
+ if(literal)
+ {
+ val = get_byte(ctx);
+ }
+ else
+ {
+ val = get(ctx->outbuf)[src++];
+ }
+ membuf_append_char(ctx->outbuf, val);
+ } while (--len > 0);
+
+ }
+}
+
+int flagind = 1;
+int flagflag = '?';
+const char *flagarg = NULL;
+
+static void reverse(char **buf, int pos1, int pos2)
+{
+ char **buf1;
+ char **buf2;
+ char *tmp;
+
+ buf1 = buf + pos1;
+ buf2 = buf + pos2 - 1;
+
+ while (buf1 < buf2)
+ {
+ tmp = *buf1;
+ *buf1 = *buf2;
+ *buf2 = tmp;
+
+ ++buf1;
+ --buf2;
+ }
+}
+
+
+int getflag(int argc, char **argv, const char *flags)
+{
+ int argstart, flagstart, c;
+ const char *flagp;
+
+ c = -1;
+ flagarg = NULL;
+ argstart = flagind;
+ flagstart = argc;
+
+ /* skip over non-flags */
+ while (flagind < argc && argv[flagind][0] != '-')
+ {
+ ++flagind;
+ }
+ if (flagind == argc)
+ {
+ /* no more args */
+ flagind = argstart;
+ return c;
+ }
+ /* we have an arg to work with */
+ do
+ {
+ flagstart = flagind;
+ if (argv[flagind][1] == '-' && argv[flagind][2] == '\0')
+ {
+ /* stop parsing at '--' flag */
+ break;
+ }
+ c = flagflag = argv[flagind][1];
+ if (c == ':' || c == '\0')
+ {
+ /* this is an illegal flag */
+ c = '?';
+ break;
+ }
+ /* flag with arg */
+ if (argv[flagind][2] != '\0')
+ {
+ /* flag-arg in same argv[] */
+ flagarg = argv[flagind] + 2;
+ }
+ flagp = strchr(flags, c);
+ if (flagp == NULL)
+ {
+ /* this is an unknown flag */
+ c = '?';
+ break;
+ }
+ if (flagarg != NULL || flagp[1] != ':')
+ {
+ if (flagarg != NULL && flagp[1] != ':')
+ {
+ /* error, a simple flag with an argument */
+ c = '?';
+ }
+ break;
+ }
+
+ /* flag-arg is in the next argv[] */
+ if (flagind + 1 == argc)
+ {
+ /* auahh, no flag-arg */
+ flagstart = argstart;
+ c = '?';
+ break;
+ }
+ flagarg = argv[++flagind];
+ } while (0);
+ /* skip to next arg */
+ ++flagind;
+
+ if (flagstart < flagind && argstart < flagstart)
+ {
+ /* we have found some args
+ * we have also skipped over some non-args
+ * shuffle the non-flag arg to the end of argv */
+ reverse(argv, argstart, flagstart);
+ reverse(argv, flagstart, flagind);
+ reverse(argv, argstart, flagind);
+ }
+ flagind = argstart + flagind - flagstart;
+
+ return c;
+}
+
+struct log_output {
+ enum log_level min;
+ enum log_level max;
+ FILE *stream;
+ log_formatter_f *f;
+};
+
+struct log_ctx {
+ enum log_level level;
+ int out_len;
+ struct log_output *out;
+ int buf_len;
+ char *buf;
+};
+
+struct log_ctx *G_log_ctx = NULL;
+enum log_level G_log_level = LOG_MIN;
+enum log_level G_log_log_level = 0;
+
+struct log_ctx *log_new(void)
+{
+ struct log_ctx *ctx;
+
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ {
+ fprintf(stderr,
+ "fatal error, can't allocate memory for log context\n");
+ exit(1);
+ }
+ ctx->level = LOG_NORMAL;
+ ctx->out_len = 0;
+ ctx->out = NULL;
+ ctx->buf_len = 0;
+ ctx->buf = NULL;
+
+ return ctx;
+}
+
+/* log_delete closes all added output streams
+ * and files except for stdout and stderr
+ */
+void log_delete(struct log_ctx *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->out_len; ++i)
+ {
+ FILE *file = ctx->out[i].stream;
+ if (file != stderr && file != stdout)
+ {
+ fclose(file);
+ }
+ }
+ free(ctx->out);
+ free(ctx->buf);
+ free(ctx);
+}
+
+void log_set_level(struct log_ctx *ctx, /* IN/OUT */
+ enum log_level level) /* IN */
+{
+ ctx->level = level;
+}
+
+void log_add_output_stream(struct log_ctx *ctx, /* IN/OUT */
+ enum log_level min, /* IN */
+ enum log_level max, /* IN */
+ log_formatter_f * default_f, /* IN */
+ FILE * out_stream) /* IN */
+{
+ struct log_output *out;
+
+ ctx->out_len += 1;
+ ctx->out = realloc(ctx->out, ctx->out_len * sizeof(*(ctx->out)));
+ if (ctx->out == NULL)
+ {
+ fprintf(stderr,
+ "fatal error, can't allocate memory for log output\n");
+ exit(1);
+ }
+ out = &(ctx->out[ctx->out_len - 1]);
+ out->min = min;
+ out->max = max;
+ out->stream = out_stream;
+ out->f = default_f;
+}
+
+void raw_log_formatter(FILE * out, /* IN */
+ enum log_level level, /* IN */
+ const char *context, /* IN */
+ const char *log) /* IN */
+{
+ fprintf(out, "%s", log);
+ fflush(out);
+}
+
+void log_vlog(struct log_ctx *ctx, /* IN */
+ enum log_level level, /* IN */
+ const char *context, /* IN */
+ log_formatter_f * f, /* IN */
+ const char *printf_str, /* IN */
+ va_list argp)
+{
+ int len;
+ int i;
+
+ if (ctx->level < level)
+ {
+ /* don't log this */
+ return;
+ }
+
+ len = 0;
+ do
+ {
+ if (len >= ctx->buf_len)
+ {
+ ctx->buf_len = len + 1024;
+ ctx->buf = realloc(ctx->buf, ctx->buf_len);
+ if (ctx->buf == NULL)
+ {
+ fprintf(stderr,
+ "fatal error, can't allocate memory for log log\n");
+ exit(1);
+ }
+ }
+ len = vsnprintf(ctx->buf, ctx->buf_len, printf_str, argp);
+ }
+
+ while (len >= ctx->buf_len);
+
+ for (i = 0; i < ctx->out_len; ++i)
+ {
+ struct log_output *o = &ctx->out[i];
+ log_formatter_f *of = f;
+
+ if (level >= o->min && level <= o->max)
+ {
+ /* generate log for this output */
+ if (of == NULL)
+ {
+ of = o->f;
+ }
+ if (of != NULL)
+ {
+ of(o->stream, level, context, ctx->buf);
+ } else
+ {
+ fprintf(o->stream, "%s\n", ctx->buf);
+ fflush(o->stream);
+ }
+ }
+ }
+}
+
+void log_log_default(const char *printf_str, /* IN */
+ ...)
+{
+ va_list argp;
+ va_start(argp, printf_str);
+ log_vlog(G_log_ctx, G_log_log_level,
+ NULL, raw_log_formatter, printf_str, argp);
+}
+
+void log_log(struct log_ctx *ctx, /* IN */
+ enum log_level level, /* IN */
+ const char *context, /* IN */
+ log_formatter_f * f, /* IN */
+ const char *printf_str, /* IN */
+ ...)
+{
+ va_list argp;
+ va_start(argp, printf_str);
+ log_vlog(ctx, level, context, f, printf_str, argp);
+}
+
+void hex_dump(int level, unsigned char *p, int len)
+{
+#if 0
+ int i;
+ int j;
+ for(i = 0; i < len;)
+ {
+ LOG(level, ("%02x", p[i]));
+ ++i;
+ if(i == len || (i & 15) == 0)
+ {
+ LOG(level, ("\t\""));
+ for(j = (i - 1) & ~15; j < i; ++j)
+ {
+ unsigned char c = p[j];
+ if(!isprint(c))
+ {
+ c = '.';
+ }
+ LOG(level, ("%c", c));
+ }
+ LOG(level, ("\"\n"));
+ }
+ else
+ {
+ LOG(level, (","));
+ }
+ }
+#endif
+}
+
+struct match_node {
+ int index;
+ struct match_node *next;
+};
+
+static
+const_matchp matches_calc(match_ctx ctx, /* IN/OUT */
+ int index); /* IN */
+
+matchp match_new(match_ctx ctx, /* IN/OUT */
+ matchp *mpp,
+ int len,
+ int offset)
+{
+ matchp m = chunkpool_malloc(ctx->m_pool);
+
+ if(len == 0)
+ {
+ LOG(LOG_ERROR, ("tried to allocate len0 match.\n"));
+ *(volatile int*)0;
+ }
+ if(len > 65535)
+ {
+ len = 65535;
+ }
+
+ m->len = len;
+ m->offset = offset;
+
+ /* insert new node in list */
+ m->next = *mpp;
+ *mpp = m;
+
+ return m;
+}
+
+
+void match_ctx_init(match_ctx ctx, /* IN/OUT */
+ struct membuf *inbuf, /* IN */
+ int max_len, /* IN */
+ int max_offset, /* IN */
+ int use_imprecise_rle) /* IN */
+{
+ struct match_node *np;
+
+ int buf_len = membuf_memlen(inbuf);
+ const unsigned char *buf = membuf_get(inbuf);
+
+ int c, i;
+ int val;
+
+ ctx->info = calloc(buf_len + 1, sizeof(*ctx->info));
+ ctx->rle = calloc(buf_len + 1, sizeof(*ctx->rle));
+ ctx->rle_r = calloc(buf_len + 1, sizeof(*ctx->rle_r));
+
+ chunkpool_init(ctx->m_pool, sizeof(match));
+
+ ctx->max_offset = max_offset;
+ ctx->max_len = max_len;
+
+ ctx->buf = buf;
+ ctx->len = buf_len;
+
+ val = buf[0];
+ for (i = 1; i < buf_len; ++i)
+ {
+ if (buf[i] == val)
+ {
+ int len = ctx->rle[i - 1] + 1;
+ if(len > 65535)
+ {
+ len = 0;
+ }
+ ctx->rle[i] = len;
+ } else
+ {
+ ctx->rle[i] = 0;
+ }
+ val = buf[i];
+ }
+
+ for (i = buf_len - 2; i >= 0; --i)
+ {
+ if (ctx->rle[i] < ctx->rle[i + 1])
+ {
+ ctx->rle_r[i] = ctx->rle_r[i + 1] + 1;
+ } else
+ {
+ ctx->rle_r[i] = 0;
+ }
+ }
+
+ /* add extra nodes to rle sequences */
+ for(c = 0; c < 256; ++c)
+ {
+ static char rle_map[65536];
+ struct match_node *prev_np;
+ unsigned short int rle_len;
+
+ /* for each possible rle char */
+ memset(rle_map, 0, sizeof(rle_map));
+ prev_np = NULL;
+ for (i = 0; i < buf_len; ++i)
+ {
+ /* must be the correct char */
+ if(buf[i] != c)
+ {
+ continue;
+ }
+
+ rle_len = ctx->rle[i];
+ if(!rle_map[rle_len] && ctx->rle_r[i] > 16)
+ {
+ /* no previous lengths and not our primary length*/
+ continue;
+ }
+
+ if (use_imprecise_rle &&
+ ctx->rle_r[i] != 0 && ctx->rle[i] != 0)
+ {
+ continue;
+ }
+
+ np = chunkpool_malloc(ctx->m_pool);
+ np->index = i;
+ np->next = NULL;
+ rle_map[rle_len] = 1;
+
+ LOG(LOG_DUMP, ("0) c = %d, added np idx %d -> %d\n", c, i, 0));
+
+ /* if we have a previous entry, let's chain it together */
+ if(prev_np != NULL)
+ {
+ LOG(LOG_DUMP, ("1) c = %d, pointed np idx %d -> %d\n",
+ c, prev_np->index, i));
+ prev_np->next = np;
+ }
+
+ ctx->info[i]->single = np;
+ prev_np = np;
+ }
+
+ memset(rle_map, 0, sizeof(rle_map));
+ prev_np = NULL;
+ for (i = buf_len - 1; i >= 0; --i)
+ {
+ /* must be the correct char */
+ if(buf[i] != c)
+ {
+ continue;
+ }
+
+ rle_len = ctx->rle_r[i];
+ np = ctx->info[i]->single;
+ if(np == NULL)
+ {
+ if(rle_map[rle_len] && prev_np != NULL && rle_len > 0)
+ {
+ np = chunkpool_malloc(ctx->m_pool);
+ np->index = i;
+ np->next = prev_np;
+ ctx->info[i]->single = np;
+
+ LOG(LOG_DEBUG, ("2) c = %d, added np idx %d -> %d\n",
+ c, i, prev_np->index));
+ }
+ }
+ else
+ {
+ prev_np = np;
+ }
+
+ if(ctx->rle_r[i] > 0)
+ {
+ continue;
+ }
+ rle_len = ctx->rle[i] + 1;
+ rle_map[rle_len] = 1;
+ }
+ }
+
+
+ for (i = buf_len - 1; i >= 0; --i)
+ {
+ const_matchp matches;
+
+ /* let's populate the cache */
+ matches = matches_calc(ctx, i);
+
+ /* add to cache */
+ ctx->info[i]->cache = matches;
+
+ }
+
+}
+
+void match_ctx_free(match_ctx ctx) /* IN/OUT */
+{
+ chunkpool_free(ctx->m_pool);
+ free(ctx->info);
+ free(ctx->rle);
+ free(ctx->rle_r);
+}
+
+void dump_matches(int level, matchp mp)
+{
+ if (mp == NULL)
+ {
+ LOG(level, (" (NULL)\n"));
+ } else
+ {
+ if(mp->offset > 0)
+ {
+ LOG(level, (" offset %d, len %d\n", mp->offset, mp->len));
+ }
+ if (mp->next != NULL)
+ {
+ dump_matches(level, mp->next);
+ }
+ }
+}
+
+const_matchp matches_get(match_ctx ctx, /* IN/OUT */
+ int index) /* IN */
+{
+ return ctx->info[index]->cache;
+}
+
+/* this needs to be called with the indexes in
+ * reverse order */
+const_matchp matches_calc(match_ctx ctx, /* IN/OUT */
+ int index) /* IN */
+{
+ const unsigned char *buf;
+
+ matchp matches;
+ matchp mp;
+ struct match_node *np;
+
+ buf = ctx->buf;
+ matches = NULL;
+
+ LOG(LOG_DUMP, ("index %d, char '%c', rle %d, rle_r %d\n",
+ index, buf[index], ctx->rle[index],
+ ctx->rle_r[index]));
+
+ /* proces the literal match and add it to matches */
+ mp = match_new(ctx, &matches, 1, 0);
+
+ /* get possible match */
+ np = ctx->info[index]->single;
+ if(np != NULL)
+ {
+ np = np->next;
+ }
+ for (; np != NULL; np = np->next)
+ {
+ int mp_len;
+ int len;
+ int pos;
+ int offset;
+
+ /* limit according to max offset */
+ if(np->index > index + ctx->max_offset)
+ {
+ break;
+ }
+
+ LOG(LOG_DUMP, ("find lengths for index %d to index %d\n",
+ index, np->index));
+
+ /* get match len */
+ mp_len = mp->offset > 0 ? mp->len : 0;
+ LOG(LOG_DUMP, ("0) comparing with current best [%d] off %d len %d\n",
+ index, mp->offset, mp_len));
+
+ offset = np->index - index;
+ len = mp_len;
+ pos = index + 1 - len;
+ /* Compare the first <previous len> bytes backwards. We can
+ * skip some comparisons by increasing by the rle count. We
+ * don't need to compare the first byte, hence > 1 instead of
+ * > 0 */
+ while(len > 1 && buf[pos] == buf[pos + offset])
+ {
+#if 1
+ int offset1 = ctx->rle_r[pos];
+ int offset2 = ctx->rle_r[pos + offset];
+ int offset = offset1 < offset2 ? offset1 : offset2;
+
+ LOG(LOG_DUMP, ("1) compared sucesssfully [%d] %d %d\n",
+ index, pos, pos + offset));
+
+ len -= 1 + offset;
+ pos += 1 + offset;
+#else
+ --len;
+ ++pos;
+#endif
+ }
+ if(len > 1)
+ {
+ /* sequence length too short, skip this match */
+ continue;
+ }
+
+ if(offset < 17)
+ {
+ /* allocate match struct and add it to matches */
+ mp = match_new(ctx, &matches, 1, offset);
+ }
+
+ /* Here we know that the current match is atleast as long as
+ * the previuos one. let's compare further. */
+ len = mp_len;
+ pos = index - len;
+ while(len <= ctx->max_len &&
+ pos >= 0 && buf[pos] == buf[pos + offset])
+ {
+ LOG(LOG_DUMP, ("2) compared sucesssfully [%d] %d %d\n",
+ index, pos, pos + offset));
+ ++len;
+ --pos;
+ }
+ if(len > mp_len)
+ {
+ /* allocate match struct and add it to matches */
+ mp = match_new(ctx, &matches, index - pos, offset);
+ }
+ if (len > ctx->max_len)
+ {
+ break;
+ }
+ if(pos < 0)
+ {
+ /* we have reached the eof, no better matches can be found */
+ break;
+ }
+ }
+ LOG(LOG_DEBUG, ("adding matches for index %d to cache\n", index));
+ dump_matches(LOG_DEBUG, matches);
+
+ return matches;
+}
+
+static
+int
+matchp_keep_this(const_matchp mp)
+{
+ int val = 1;
+ /* if we want to ignore this matchp then return true else false */
+ if(mp->len == 1)
+ {
+ if(mp->offset > 32)
+ {
+ val = 0;
+ }
+ }
+ return val;
+}
+
+static
+void
+matchp_cache_peek(struct match_ctx *ctx, int pos,
+ const_matchp *litpp, const_matchp *seqpp,
+ matchp lit_tmp, matchp val_tmp)
+{
+ const_matchp litp, seqp, val;
+
+ seqp = NULL;
+ litp = NULL;
+ if(pos >= 0)
+ {
+ val = matches_get(ctx, pos);
+ litp = val;
+ while(litp->offset != 0)
+ {
+ litp = litp->next;
+ }
+
+ /* inject extra rle match */
+ if(ctx->rle_r[pos] > 0)
+ {
+ val_tmp->offset = 1;
+ val_tmp->len = ctx->rle[pos] + 1;
+ val_tmp->next = (matchp)val;
+ val = val_tmp;
+ LOG(LOG_DEBUG, ("injecting rle val(%d,%d)\n",
+ val->len, val->offset));
+ }
+
+ while(val != NULL)
+ {
+ if(val->offset != 0)
+ {
+ if(matchp_keep_this(val))
+ {
+ if(seqp == NULL || val->len > seqp->len ||
+ (val->len == seqp->len && val->offset < seqp->offset))
+ {
+ seqp = val;
+ }
+ }
+ if(litp->offset == 0 || litp->offset > val->offset)
+ {
+ LOG(LOG_DEBUG, ("val(%d,%d)", val->len, val->offset));
+ if(lit_tmp != NULL)
+ {
+ int diff;
+ match tmp2;
+ *tmp2 = *val;
+ tmp2->len = 1;
+ diff = ctx->rle[pos + val->offset];
+ if(tmp2->offset > diff)
+ {
+ tmp2->offset -= diff;
+ }
+ else
+ {
+ tmp2->offset = 1;
+ }
+ LOG(LOG_DEBUG, ("=> litp(%d,%d)",
+ tmp2->len, tmp2->offset));
+ if(matchp_keep_this(tmp2))
+ {
+ LOG(LOG_DEBUG, (", keeping"));
+ *lit_tmp = *tmp2;
+ litp = lit_tmp;
+ }
+ }
+ LOG(LOG_DEBUG, ("\n"));
+ }
+ }
+ val = val->next;
+ }
+ }
+#if 0
+ LOG(LOG_NORMAL, ("[%05d]: ", pos));
+ if(litp == NULL)
+ LOG(LOG_NORMAL, ("litp(NULL)"));
+ else
+ LOG(LOG_NORMAL, ("litp(%d,%d)", litp->len, litp->offset));
+
+ if(seqp == NULL)
+ LOG(LOG_NORMAL, ("seqp(NULL)"));
+ else
+ LOG(LOG_NORMAL, ("seqp(%d,%d)", seqp->len, seqp->offset));
+
+ LOG(LOG_NORMAL, ("\n"));
+#endif
+
+ if(litpp != NULL) *litpp = litp;
+ if(seqpp != NULL) *seqpp = seqp;
+}
+
+void matchp_cache_get_enum(match_ctx ctx, /* IN */
+ matchp_cache_enum mpce) /* IN/OUT */
+{
+ mpce->ctx = ctx;
+ mpce->pos = ctx->len - 1;
+ /*mpce->next = NULL;*/ /* two iterations */
+ mpce->next = (void*)mpce; /* just one */
+}
+
+const_matchp matchp_cache_enum_get_next(void *matchp_cache_enum)
+{
+ const_matchp val, lit, seq;
+ matchp_cache_enump mpce;
+
+ mpce = matchp_cache_enum;
+
+ restart:
+ matchp_cache_peek(mpce->ctx, mpce->pos, &lit, &seq,
+ mpce->tmp1, mpce->tmp2);
+
+ val = lit;
+ if(lit == NULL)
+ {
+ /* the end, reset enum and return NULL */
+ mpce->pos = mpce->ctx->len - 1;
+ if(mpce->next == NULL)
+ {
+ mpce->next = (void*)mpce;
+ goto restart;
+ }
+ else
+ {
+ mpce->next = NULL;
+ }
+ }
+ else
+ {
+ if(seq != NULL)
+ {
+ match t1;
+ match t2;
+ const_matchp next;
+ matchp_cache_peek(mpce->ctx, mpce->pos - 1, NULL, &next, t1 ,t2);
+ if(next == NULL ||
+ (next->len + (mpce->next != NULL && next->len < 3) <= seq->len))
+ {
+ /* nope, next is not better, use this sequence */
+ val = seq;
+ }
+ }
+ }
+ if(val != NULL)
+ {
+ LOG(LOG_DEBUG, ("Using len %05d, offset, %05d\n", val->len, val->offset));
+ mpce->pos -= val->len;
+ }
+ return val;
+}
+
+
+
+void read_file(const char *name, struct membuf *buf)
+{
+ char block[1024];
+ FILE *in;
+ int len;
+
+ in = fopen(name, "rb");
+ if(in == NULL)
+ {
+ LOG(LOG_ERROR, ("Can't open file \"%s\" for input.\n", name));
+ exit(-1);
+ }
+ do
+ {
+ len = fread(block, 1, 1024, in);
+ membuf_append(buf, block, len);
+ }
+ while(len == 1024);
+ LOG(LOG_DEBUG, ("read %d bytes from file\n", len));
+ fclose(in);
+}
+
+void write_file(const char *name, struct membuf *buf)
+{
+ FILE *out;
+ out = fopen(name, "wb");
+ if(out == NULL)
+ {
+ LOG(LOG_ERROR, ("Can't open file \"%s\" for output.\n", name));
+ exit(-1);
+ }
+ fwrite(membuf_get(buf), 1, membuf_memlen(buf), out);
+ fclose(out);
+}
+void membuf_init(struct membuf *sb)
+{
+ sb->buf = NULL;
+ sb->len = 0;
+ sb->size = 0;
+}
+void membuf_clear(struct membuf *sb)
+{
+ sb->len = 0;
+}
+void membuf_free(struct membuf *sb)
+{
+ if (sb->buf != NULL)
+ {
+ free(sb->buf);
+ sb->buf = NULL;
+ }
+ sb->len = 0;
+ sb->size = 0;
+}
+
+void membuf_new(struct membuf **sbp)
+{
+ struct membuf *sb;
+
+ sb = malloc(sizeof(struct membuf));
+ if (sb == NULL)
+ {
+ fprintf(stderr, "error, can't allocate memory\n");
+ exit(1);
+ }
+ sb->buf = NULL;
+ sb->len = 0;
+ sb->size = 0;
+
+ *sbp = sb;
+}
+
+void membuf_delete(struct membuf **sbp)
+{
+ struct membuf *sb;
+
+ sb = *sbp;
+ membuf_free(sb);
+ free(sb);
+ sb = NULL;
+ *sbp = sb;
+}
+
+int membuf_memlen(const struct membuf *sb)
+{
+ return sb->len;
+}
+
+void membuf_truncate(struct membuf *sb, int len)
+{
+ sb->len = len;
+}
+
+int membuf_trim(struct membuf *sb, int pos)
+{
+ if(pos < 0 || pos > sb->len)
+ {
+ return -1;
+ }
+ if(pos == 0)
+ {
+ return sb->len;
+ }
+ if(pos != sb->len)
+ {
+ memmove(sb->buf, (char*)sb->buf + pos, sb->len - pos);
+ }
+ sb->len -= pos;
+ return sb->len;
+}
+
+void *membuf_memcpy(struct membuf *sb, int offset, const void *mem, int len)
+{
+ char *buf;
+ membuf_atleast(sb, offset + len);
+ buf = (char*)sb->buf + offset;
+ memcpy(buf, mem, len);
+ return buf;
+}
+
+void *membuf_append(struct membuf *sb, const void *mem, int len)
+{
+ int newlen;
+ void *p;
+ newlen = sb->len + len;
+ membuf_atleast(sb, newlen);
+ p = (char *) sb->buf + sb->len;
+ if(mem == NULL)
+ {
+ memset(p, 0, len);
+ }
+ else
+ {
+ memcpy(p, mem, len);
+ }
+ sb->len = newlen;
+ return p;
+}
+
+void *membuf_append_char(struct membuf *sb, char c)
+{
+ int newlen;
+ char *p;
+ newlen = sb->len + 1;
+ membuf_atleast(sb, newlen);
+ p = (char *) sb->buf + sb->len;
+ *p = c;
+ sb->len = newlen;
+ return p;
+}
+
+void *membuf_insert(struct membuf *sb, int offset, const void *mem, int len)
+{
+ int newlen;
+ void *from;
+ void *to;
+ newlen = sb->len + len;
+ membuf_atleast(sb, newlen);
+ from = (char *)sb->buf + offset;
+ to = (char *)from + len;
+ memmove(to, from, sb->len - offset);
+ if(mem == NULL)
+ {
+ memset(from, 0, len);
+ }
+ else
+ {
+ memcpy(from, mem, len);
+ }
+ sb->len = newlen;
+ return from;
+}
+
+void membuf_remove(struct membuf *sb, int offset, int len)
+{
+ void *from;
+ void *to;
+ to = (char *)sb->buf + offset;
+ from = (char *)to + len;
+ sb->len -= len;
+ memmove(to, from, sb->len - offset);
+
+}
+
+void membuf_atleast(struct membuf *sb, int len)
+{
+ int size;
+
+ size = sb->size;
+ if (size == 0)
+ size = 1;
+ while (size < len)
+ {
+ size <<= 1;
+ }
+ if (size > sb->size)
+ {
+ sb->buf = realloc(sb->buf, size);
+ if (sb->buf == NULL)
+ {
+ fprintf(stderr, "error, can't reallocate memory\n");
+ exit(1);
+ }
+ sb->size = size;
+ }
+}
+
+void membuf_atmost(struct membuf *sb, int len)
+{
+ int size;
+
+ size = sb->size;
+ while (size > len)
+ {
+ size >>= 1;
+ }
+ if (size < sb->size)
+ {
+ sb->buf = realloc(sb->buf, size);
+ if (sb->buf == NULL)
+ {
+ fprintf(stderr, "error, can't reallocate memory\n");
+ exit(1);
+ }
+ sb->size = size;
+ sb->len = size;
+ }
+}
+
+int membuf_get_size(const struct membuf *sb)
+{
+ return sb->size;
+}
+void *membuf_get(const struct membuf *sb)
+{
+ return sb->buf;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct _interval_node {
+ int start;
+ int score;
+ struct _interval_node *next;
+ signed char prefix;
+ signed char bits;
+ signed char depth;
+ signed char flags;
+};
+
+typedef struct _interval_node interval_node[1];
+typedef struct _interval_node *interval_nodep;
+
+static
+void
+interval_node_init(interval_nodep inp, int start, int depth, int flags)
+{
+ inp->start = start;
+ inp->flags = flags;
+ inp->depth = depth;
+ inp->bits = 0;
+ inp->prefix = flags >= 0 ? flags : depth + 1;
+ inp->score = -1;
+ inp->next = NULL;
+}
+
+static
+interval_nodep interval_node_clone(interval_nodep inp)
+{
+ interval_nodep inp2 = NULL;
+
+ if(inp != NULL)
+ {
+ inp2 = malloc(sizeof(interval_node));
+ if (inp2 == NULL)
+ {
+ LOG(LOG_ERROR, ("out of memory error in file %s, line %d\n",
+ __FILE__, __LINE__));
+ exit(0);
+ }
+ /* copy contents */
+ *inp2 = *inp;
+ inp2->next = interval_node_clone(inp->next);
+ }
+
+ return inp2;
+}
+
+static
+void interval_node_delete(interval_nodep inp)
+{
+ interval_nodep inp2;
+ while (inp != NULL)
+ {
+ inp2 = inp;
+ inp = inp->next;
+ free(inp2);
+ }
+}
+
+static
+void interval_node_dump(int level, interval_nodep inp)
+{
+ int end;
+
+ end = 0;
+ while (inp != NULL)
+ {
+ end = inp->start + (1 << inp->bits);
+ LOG(level, ("%X", inp->bits));
+ inp = inp->next;
+ }
+ LOG(level, ("[eol@%d]\n", end));
+}
+
+float optimal_encode_int(int arg, void *priv, output_ctxp out)
+{
+ interval_nodep inp;
+ int end;
+
+ float val;
+
+ inp = (interval_nodep) priv;
+ val = 100000000.0;
+ end = 0;
+ while (inp != NULL)
+ {
+ end = inp->start + (1 << inp->bits);
+ if (arg >= inp->start && arg < end)
+ {
+ break;
+ }
+ inp = inp->next;
+ }
+ if (inp != NULL)
+ {
+ val = (float) (inp->prefix + inp->bits);
+ } else
+ {
+ val += (float) (arg - end);
+ }
+ LOG(LOG_DUMP, ("encoding %d to %0.1f bits\n", arg, val));
+
+ if (out != NULL)
+ {
+ output_bits(out, inp->bits, arg - inp->start);
+ if (inp->flags < 0)
+ {
+ LOG(LOG_DUMP, ("gamma prefix code = %d\n", inp->depth));
+ output_gamma_code(out, inp->depth);
+ } else
+ {
+ LOG(LOG_DUMP, ("flat prefix %d bits\n", inp->depth));
+ output_bits(out, inp->prefix, inp->depth);
+ }
+ }
+
+ return val;
+}
+
+float optimal_encode(const_matchp mp, encode_match_data emd)
+{
+ interval_nodep *offset;
+ float bits;
+ encode_match_privp data;
+
+ data = emd->priv;
+ offset = data->offset_f_priv;
+
+ bits = 0.0;
+ if (mp->offset == 0)
+ {
+ bits += 9.0f * mp->len;
+ data->lit_num += mp->len;
+ data->lit_bits += bits;
+ } else
+ {
+ bits += 1.0;
+ switch (mp->len)
+ {
+ case 0:
+ LOG(LOG_ERROR, ("bad len\n"));
+ exit(1);
+ break;
+ case 1:
+ bits += data->offset_f(mp->offset, offset[0], emd->out);
+ break;
+ case 2:
+ bits += data->offset_f(mp->offset, offset[1], emd->out);
+ break;
+ default:
+ bits += data->offset_f(mp->offset, offset[7], emd->out);
+ break;
+ }
+ bits += data->len_f(mp->len, data->len_f_priv, emd->out);
+ if (bits > (9.0 * mp->len))
+ {
+ /* lets make literals out of it */
+ data->lit_num += 1;
+ data->lit_bits += bits;
+ } else
+ {
+ if (mp->offset == 1)
+ {
+ data->rle_num += 1;
+ data->rle_bits += bits;
+ } else
+ {
+ data->seq_num += 1;
+ data->seq_bits += bits;
+ }
+ }
+ }
+ return bits;
+}
+
+struct _optimize_arg {
+ radix_root cache;
+ int *stats;
+ int *stats2;
+ int max_depth;
+ int flags;
+ struct chunkpool in_pool[1];
+};
+
+#define CACHE_KEY(START, DEPTH, MAXDEPTH) ((int)((START)*(MAXDEPTH)|DEPTH))
+
+typedef struct _optimize_arg optimize_arg[1];
+typedef struct _optimize_arg optimize_argp;
+
+static interval_nodep
+optimize1(optimize_arg arg, int start, int depth, int init)
+{
+ interval_node inp;
+ interval_nodep best_inp;
+ int key;
+ int end, i;
+ int start_count, end_count;
+
+ LOG(LOG_DUMP, ("IN start %d, depth %d\n", start, depth));
+
+ do
+ {
+ best_inp = NULL;
+ if (arg->stats[start] == 0)
+ {
+ break;
+ }
+ key = CACHE_KEY(start, depth, arg->max_depth);
+ best_inp = radix_node_get(arg->cache, key);
+ if (best_inp != NULL)
+ {
+ break;
+ }
+
+ interval_node_init(inp, start, depth, arg->flags);
+
+ for (i = 0; i < 16; ++i)
+ {
+ inp->next = NULL;
+ inp->bits = i;
+ end = start + (1 << i);
+
+ start_count = end_count = 0;
+ if (start < 65536)
+ {
+ start_count = arg->stats[start];
+ if (end < 65536)
+ {
+ end_count = arg->stats[end];
+ }
+ }
+
+ inp->score = (start_count - end_count) *
+ (inp->prefix + inp->bits);
+
+ /* one index below */
+ LOG(LOG_DUMP, ("interval score: [%d«%d[%d\n",
+ start, i, inp->score));
+ if (end_count > 0)
+ {
+ int penalty;
+ /* we're not done, now choose between using
+ * more bits, go deeper or skip the rest */
+ if (depth + 1 < arg->max_depth)
+ {
+ /* we can go deeper, let's try that */
+ inp->next = optimize1(arg, end, depth + 1, i);
+ }
+ /* get the penalty for skipping */
+ penalty = 100000000;
+ if (arg->stats2 != NULL)
+ {
+ penalty = arg->stats2[end];
+ }
+ if (inp->next != NULL && inp->next->score < penalty)
+ {
+ penalty = inp->next->score;
+ }
+ inp->score += penalty;
+ }
+ if (best_inp == NULL || inp->score < best_inp->score)
+ {
+ /* it's the new best in town, use it */
+ if (best_inp == NULL)
+ {
+ /* allocate if null */
+ best_inp = chunkpool_malloc(arg->in_pool);
+ }
+ *best_inp = *inp;
+ }
+ }
+ if (best_inp != NULL)
+ {
+ radix_node_set(arg->cache, key, best_inp);
+ }
+ }
+ while (0);
+
+ if(IS_LOGGABLE(LOG_DUMP))
+ {
+ LOG(LOG_DUMP, ("OUT depth %d: ", depth));
+ interval_node_dump(LOG_DUMP, best_inp);
+ }
+ return best_inp;
+}
+
+static interval_nodep
+exo_optimize(int stats[65536], int stats2[65536], int max_depth, int flags)
+{
+ optimize_arg arg;
+
+ interval_nodep inp;
+
+ arg->stats = stats;
+ arg->stats2 = stats2;
+
+ arg->max_depth = max_depth;
+ arg->flags = flags;
+
+ chunkpool_init(arg->in_pool, sizeof(interval_node));
+
+ radix_tree_init(arg->cache);
+
+ inp = optimize1(arg, 1, 0, 0);
+
+ /* use normal malloc for the winner */
+ inp = interval_node_clone(inp);
+
+ /* cleanup */
+ radix_tree_free(arg->cache, NULL, NULL);
+ chunkpool_free(arg->in_pool);
+
+ return inp;
+}
+
+static const char *export_helper(interval_nodep np, int depth)
+{
+ static char buf[20];
+ char *p = buf;
+ while(np != NULL)
+ {
+ p += sprintf(p, "%X", np->bits);
+ np = np->next;
+ --depth;
+ }
+ while(depth-- > 0)
+ {
+ p += sprintf(p, "0");
+ }
+ return buf;
+}
+
+const char *optimal_encoding_export(encode_match_data emd)
+{
+ interval_nodep *offsets;
+ static char buf[100];
+ char *p = buf;
+ encode_match_privp data;
+ data = emd->priv;
+ offsets = (interval_nodep*)data->offset_f_priv;
+ p += sprintf(p, "%s", export_helper((interval_nodep)data->len_f_priv, 16));
+ p += sprintf(p, ",%s", export_helper(offsets[0], 4));
+ p += sprintf(p, ",%s", export_helper(offsets[1], 16));
+ p += sprintf(p, ",%s", export_helper(offsets[7], 16));
+ return buf;
+}
+
+static void import_helper(interval_nodep *npp,
+ const char **encodingp,
+ int flags)
+{
+ int c;
+ int start = 1;
+ int depth = 0;
+ const char *encoding;
+
+ encoding = *encodingp;
+ while((c = *(encoding++)) != '\0')
+ {
+ char buf[2] = {0, 0};
+ char *dummy;
+ int bits;
+ interval_nodep np;
+
+ if(c == ',')
+ {
+ break;
+ }
+
+ buf[0] = c;
+ bits = strtol(buf, &dummy, 16);
+
+ LOG(LOG_DUMP, ("got bits %d\n", bits));
+
+ np = malloc(sizeof(interval_node));
+ interval_node_init(np, start, depth, flags);
+ np->bits = bits;
+
+ ++depth;
+ start += 1 << bits;
+
+ *npp = np;
+ npp = &(np->next);
+ }
+ *encodingp = encoding;
+}
+
+void optimal_encoding_import(encode_match_data emd,
+ const char *encoding)
+{
+ encode_match_privp data;
+ interval_nodep *npp, *offsets;
+
+ LOG(LOG_DEBUG, ("importing encoding: %s\n", encoding));
+
+ optimal_free(emd);
+ optimal_init(emd);
+
+ data = emd->priv;
+ offsets = (interval_nodep*)data->offset_f_priv;
+
+ /* lengths */
+ npp = (void*)&data->len_f_priv;
+ import_helper(npp, &encoding, -1);
+
+ /* offsets, len = 1 */
+ npp = &offsets[0];
+ import_helper(npp, &encoding, 2);
+
+ /* offsets, len = 2 */
+ npp = &offsets[1];
+ import_helper(npp, &encoding, 4);
+
+ /* offsets, len >= 3 */
+ npp = &offsets[7];
+ import_helper(npp, &encoding, 4);
+
+ LOG(LOG_DEBUG, ("imported encoding: "));
+ optimal_dump(LOG_DEBUG, emd);
+}
+
+void optimal_init(encode_match_data emd) /* IN/OUT */
+{
+ encode_match_privp data;
+ interval_nodep *inpp;
+
+ emd->priv = malloc(sizeof(encode_match_priv));
+ data = emd->priv;
+
+ memset(data, 0, sizeof(encode_match_priv));
+
+ data->offset_f = optimal_encode_int;
+ data->len_f = optimal_encode_int;
+ inpp = malloc(sizeof(interval_nodep[8]));
+ inpp[0] = NULL;
+ inpp[1] = NULL;
+ inpp[2] = NULL;
+ inpp[3] = NULL;
+ inpp[4] = NULL;
+ inpp[5] = NULL;
+ inpp[6] = NULL;
+ inpp[7] = NULL;
+ data->offset_f_priv = inpp;
+ data->len_f_priv = NULL;
+}
+
+void optimal_free(encode_match_data emd) /* IN */
+{
+ encode_match_privp data;
+ interval_nodep *inpp;
+ interval_nodep inp;
+
+ data = emd->priv;
+
+ inpp = data->offset_f_priv;
+ if (inpp != NULL)
+ {
+ interval_node_delete(inpp[0]);
+ interval_node_delete(inpp[1]);
+ interval_node_delete(inpp[2]);
+ interval_node_delete(inpp[3]);
+ interval_node_delete(inpp[4]);
+ interval_node_delete(inpp[5]);
+ interval_node_delete(inpp[6]);
+ interval_node_delete(inpp[7]);
+ }
+ free(inpp);
+
+ inp = data->len_f_priv;
+ interval_node_delete(inp);
+
+ data->offset_f_priv = NULL;
+ data->len_f_priv = NULL;
+}
+
+void freq_stats_dump(int level, int arr[65536])
+{
+ int i;
+ for (i = 0; i < 32; ++i)
+ {
+ LOG(level, ("%d, ", arr[i] - arr[i + 1]));
+ }
+ LOG(level, ("\n"));
+}
+
+void freq_stats_dump_raw(int level, int arr[65536])
+{
+ int i;
+ for (i = 0; i < 32; ++i)
+ {
+ LOG(level, ("%d, ", arr[i]));
+ }
+ LOG(level, ("\n"));
+}
+
+void optimal_optimize(encode_match_data emd, /* IN/OUT */
+ matchp_enum_get_next_f * f, /* IN */
+ void *matchp_enum) /* IN */
+{
+ encode_match_privp data;
+ const_matchp mp;
+ interval_nodep *offset;
+ static int offset_arr[8][65536];
+ static int offset_parr[8][65536];
+ static int len_arr[65536];
+ int treshold;
+
+ int i, j;
+ void *priv1;
+
+ data = emd->priv;
+
+ memset(offset_arr, 0, sizeof(offset_arr));
+ memset(offset_parr, 0, sizeof(offset_parr));
+ memset(len_arr, 0, sizeof(len_arr));
+
+ offset = data->offset_f_priv;
+
+ /* first the lens */
+ priv1 = matchp_enum;
+#if 0
+ while ((mp = f(priv1)) != NULL)
+ {
+ LOG(LOG_DEBUG, ("%p len %d offset %d\n", mp, mp->len, mp->offset));
+ }
+ if(mp->len < 0)
+ {
+ LOG(LOG_ERROR, ("the horror, negative len!\n"));
+ }
+#endif
+ while ((mp = f(priv1)) != NULL && mp->len > 0)
+ {
+ if (mp->offset > 0)
+ {
+ len_arr[mp->len] += 1;
+ if(len_arr[mp->len] < 0)
+ {
+ LOG(LOG_ERROR, ("len counter wrapped!\n"));
+ }
+ }
+ }
+
+ for (i = 65534; i >= 0; --i)
+ {
+ len_arr[i] += len_arr[i + 1];
+ if(len_arr[i] < 0)
+ {
+ LOG(LOG_ERROR, ("len counter wrapped!\n"));
+ }
+ }
+
+ data->len_f_priv = exo_optimize(len_arr, NULL, 16, -1);
+
+ /* then the offsets */
+ priv1 = matchp_enum;
+ while ((mp = f(priv1)) != NULL && mp->len > 0)
+ {
+ if (mp->offset > 0)
+ {
+ treshold = mp->len * 9;
+ treshold -= 1 + (int) optimal_encode_int(mp->len,
+ data->len_f_priv,
+ NULL);
+ switch (mp->len)
+ {
+ case 0:
+ LOG(LOG_ERROR, ("bad len\n"));
+ exit(0);
+ break;
+ case 1:
+ offset_parr[0][mp->offset] += treshold;
+ offset_arr[0][mp->offset] += 1;
+ if(offset_arr[0][mp->offset] < 0)
+ {
+ LOG(LOG_ERROR, ("offset0 counter wrapped!\n"));
+ }
+ break;
+ case 2:
+ offset_parr[1][mp->offset] += treshold;
+ offset_arr[1][mp->offset] += 1;
+ if(offset_arr[1][mp->offset] < 0)
+ {
+ LOG(LOG_ERROR, ("offset1 counter wrapped!\n"));
+ }
+ break;
+ default:
+ offset_parr[7][mp->offset] += treshold;
+ offset_arr[7][mp->offset] += 1;
+ if(offset_arr[7][mp->offset] < 0)
+ {
+ LOG(LOG_ERROR, ("offset7 counter wrapped!\n"));
+ }
+ break;
+ }
+ }
+ }
+
+ for (i = 65534; i >= 0; --i)
+ {
+ for (j = 0; j < 8; ++j)
+ {
+ offset_arr[j][i] += offset_arr[j][i + 1];
+ offset_parr[j][i] += offset_parr[j][i + 1];
+ }
+ }
+
+ offset[0] = exo_optimize(offset_arr[0], offset_parr[0], 1 << 2, 2);
+ offset[1] = exo_optimize(offset_arr[1], offset_parr[1], 1 << 4, 4);
+ offset[2] = exo_optimize(offset_arr[2], offset_parr[2], 1 << 4, 4);
+ offset[3] = exo_optimize(offset_arr[3], offset_parr[3], 1 << 4, 4);
+ offset[4] = exo_optimize(offset_arr[4], offset_parr[4], 1 << 4, 4);
+ offset[5] = exo_optimize(offset_arr[5], offset_parr[5], 1 << 4, 4);
+ offset[6] = exo_optimize(offset_arr[6], offset_parr[6], 1 << 4, 4);
+ offset[7] = exo_optimize(offset_arr[7], offset_parr[7], 1 << 4, 4);
+
+ if(IS_LOGGABLE(LOG_DEBUG))
+ {
+ optimal_dump(LOG_DEBUG, emd);
+ }
+}
+
+void optimal_dump(int level, encode_match_data emd)
+{
+ encode_match_privp data;
+ interval_nodep *offset;
+ interval_nodep len;
+
+ data = emd->priv;
+
+ offset = data->offset_f_priv;
+ len = data->len_f_priv;
+
+ LOG(level, ("lens: "));
+ interval_node_dump(level, len);
+
+ LOG(level, ("offsets (len =1): "));
+ interval_node_dump(level, offset[0]);
+
+ LOG(level, ("offsets (len =2): "));
+ interval_node_dump(level, offset[1]);
+
+ LOG(level, ("offsets (len =8): "));
+ interval_node_dump(level, offset[7]);
+}
+
+static
+void interval_out(output_ctx out, interval_nodep inp1, int size)
+{
+ unsigned char buffer[256];
+ unsigned char count;
+ interval_nodep inp;
+
+ count = 0;
+
+ memset(buffer, 0, sizeof(buffer));
+ inp = inp1;
+ while (inp != NULL)
+ {
+ ++count;
+ LOG(LOG_DUMP, ("bits %d, lo %d, hi %d\n",
+ inp->bits, inp->start & 0xFF, inp->start >> 8));
+ buffer[sizeof(buffer) - count] = inp->bits;
+ inp = inp->next;
+ }
+
+ while (size > 0)
+ {
+ int b;
+ b = buffer[sizeof(buffer) - size];
+ LOG(LOG_DUMP, ("outputting nibble %d\n", b));
+ output_bits(out, 4, b);
+ size--;
+ }
+}
+
+void optimal_out(output_ctx out, /* IN/OUT */
+ encode_match_data emd) /* IN */
+{
+ encode_match_privp data;
+ interval_nodep *offset;
+ interval_nodep len;
+
+ data = emd->priv;
+
+ offset = data->offset_f_priv;
+ len = data->len_f_priv;
+
+ interval_out(out, offset[0], 4);
+ interval_out(out, offset[1], 16);
+ interval_out(out, offset[7], 16);
+ interval_out(out, len, 16);
+}
+
+void output_ctx_init(output_ctx ctx, struct membuf *out) /* IN/OUT */
+{
+ ctx->bitbuf = 1;
+ ctx->pos = membuf_memlen(out);
+ ctx->buf = out;
+}
+
+unsigned int output_get_pos(output_ctx ctx) /* IN */
+{
+ return ctx->pos;
+}
+
+void output_byte(output_ctx ctx, /* IN/OUT */
+ unsigned char byte) /* IN */
+{
+ /*LOG(LOG_DUMP, ("output_byte: $%02X\n", byte)); */
+ if(ctx->pos < membuf_memlen(ctx->buf))
+ {
+ char *p;
+ p = membuf_get(ctx->buf);
+ p[ctx->pos] = byte;
+ }
+ else
+ {
+ while(ctx->pos > membuf_memlen(ctx->buf))
+ {
+ membuf_append_char(ctx->buf, '\0');
+ }
+ membuf_append_char(ctx->buf, byte);
+ }
+ ++(ctx->pos);
+}
+
+void output_word(output_ctx ctx, /* IN/OUT */
+ unsigned short int word) /* IN */
+{
+ output_byte(ctx, (unsigned char) (word & 0xff));
+ output_byte(ctx, (unsigned char) (word >> 8));
+}
+
+
+void output_bits_flush(output_ctx ctx) /* IN/OUT */
+{
+ /* flush the bitbuf including
+ * the extra 1 bit acting as eob flag */
+ output_byte(ctx, (unsigned char) (ctx->bitbuf & 0xFF));
+ if (ctx->bitbuf & 0x100)
+ {
+ output_byte(ctx, 1);
+ }
+ LOG(LOG_DUMP, ("bitstream flushed 0x%02X\n", ctx->bitbuf & 0xFF));
+
+ /* reset it */
+ ctx->bitbuf = 1;
+}
+
+void bits_dump(int count, int val)
+{
+ static char buf[1024];
+ char *pek;
+ pek = buf;
+ if (count > 0)
+ {
+ pek += sprintf(pek, "0x%04X, % 2d: ", val, count);
+ }
+ while (count-- > 0)
+ {
+ *(pek++) = val & (1 << count) ? '1' : '0';
+ }
+ *(pek++) = '\0';
+ LOG(LOG_NORMAL, ("%s\n", buf));
+}
+
+static void output_bits_int(output_ctx ctx, /* IN/OUT */
+ int count, /* IN */
+ int val) /* IN */
+{
+ /* this makes the bits appear in reversed
+ * big endian order in the output stream */
+ while (count-- > 0)
+ {
+ ctx->bitbuf <<= 1;
+ ctx->bitbuf |= val & 0x1;
+ val >>= 1;
+ if (ctx->bitbuf & 0x100)
+ {
+ /* full byte, flush it */
+ output_byte(ctx, (unsigned char) (ctx->bitbuf & 0xFF));
+ LOG(LOG_DUMP,
+ ("bitstream byte 0x%02X\n", ctx->bitbuf & 0xFF));
+ ctx->bitbuf = 1;
+ }
+ }
+}
+
+void output_bits(output_ctx ctx, /* IN/OUT */
+ int count, /* IN */
+ int val) /* IN */
+{
+ LOG(LOG_DUMP, ("output bits: count = %d, val = %d\n", count, val));
+ output_bits_int(ctx, count, val);
+}
+
+void output_gamma_code(output_ctx ctx, /* IN/OUT */
+ int code) /* IN */
+{
+ LOG(LOG_DUMP, ("output gamma: code = %d\n", code));
+ output_bits_int(ctx, 1, 1);
+ while (code-- > 0)
+ {
+ output_bits_int(ctx, 1, 0);
+ }
+}
+
+static
+void print_usage(const char *appl, enum log_level level,
+ const char *default_out_name)
+{
+ LOG(level, ("usage: %s [option]... infile\n", appl));
+ LOG(level,
+ (" -b crunch/decrunch backwards\n"
+ " -r write outfile in reverse order\n"
+ " -d decrunch (instead of crunch)\n"));
+ print_crunch_flags(level, default_out_name);
+}
+
+#define DEFAULT_OUTFILE "a.out"
+
+unsigned char *Exomizer_crunch(unsigned char *input_data, int input_len, int *retlen)
+{
+ int argc=1;
+ char **argv=NULL;
+ char flags_arr[32];
+ int decrunch_mode = 0;
+ int backwards_mode = 0;
+ int reverse_mode = 0;
+ int c, infilec;
+ char **infilev;
+ /* output buffer */
+ unsigned char *output_data;
+
+ static struct crunch_options options[1] = { CRUNCH_OPTIONS_DEFAULT };
+ struct common_flags flags[1] = { {options, DEFAULT_OUTFILE} };
+
+ struct membuf inbuf[1];
+ struct membuf outbuf[1];
+
+ const char *appl;;
+
+
+ argv=malloc(sizeof(char *));
+ argv[0]=strdup("mem_exomizer");
+ /* init args */
+ appl = fixup_appl(argv[0]);
+
+ sprintf(flags_arr, "bdr%s", CRUNCH_FLAGS);
+ while ((c = getflag(argc, argv, flags_arr)) != -1)
+ {
+ switch (c)
+ {
+ case 'b':
+ backwards_mode = 1;
+ break;
+ case 'r':
+ reverse_mode = 1;
+ break;
+ default:
+ handle_crunch_flags(c, flagarg, print_usage, appl, flags);
+ }
+ }
+
+ infilev = argv + flagind;
+ infilec = argc - flagind;
+
+
+printf("crunching with exomizer (the art of patience...)\n");
+
+/* only memory */
+
+ membuf_init(inbuf);
+ membuf_init(outbuf);
+
+ /* rustine */
+ membuf_append(inbuf, input_data, input_len);
+
+
+ {
+ struct crunch_info info[1];
+ if(backwards_mode)
+ {
+ crunch_backwards(inbuf, outbuf, options, info);
+ }
+ else
+ {
+ exocrunch(inbuf, outbuf, options, info);
+ }
+ }
+
+ if(reverse_mode)
+ {
+ reverse_buffer(membuf_get(outbuf), membuf_memlen(outbuf));
+ }
+
+ output_data=MemMalloc(membuf_memlen(outbuf));
+ memcpy(output_data,membuf_get(outbuf),membuf_memlen(outbuf));
+ *retlen=membuf_memlen(outbuf);
+
+ membuf_free(outbuf);
+ membuf_free(inbuf);
+
+ return output_data;
+}
diff --git a/tools/rasm_src/lz4.h b/tools/rasm_src/lz4.h new file mode 100644 index 0000000..f34bae4 --- /dev/null +++ b/tools/rasm_src/lz4.h @@ -0,0 +1,3329 @@ +/* + +Warning! This is a modified version of original sources! + +To sum up: +- all include files and C sources were merged in a single file +- existing logs were removed (except error logs) +- main were removed and wrapper added + + + * LZ4 - Fast LZ compression algorithm + * Header File + * Copyright (C) 2011-2017, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ +#if defined (__cplusplus) +extern "C" { +#endif + +#ifndef LZ4_H_2983827168210 +#define LZ4_H_2983827168210 + +/* --- Dependency --- */ + + +/** + Introduction + + LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, + scalable with multi-cores CPU. It features an extremely fast decoder, with speed in + multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. + + The LZ4 compression library provides in-memory compression and decompression functions. + Compression can be done in: + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) + + lz4.h provides block compression functions. It gives full buffer control to user. + Decompressing an lz4-compressed block also requires metadata (such as compressed size). + Each application is free to encode such metadata in whichever way it wants. + + An additional format, called LZ4 frame specification (doc/lz4_Frame_format.md), + take care of encoding standard metadata alongside LZ4-compressed blocks. + If your application requires interoperability, it's recommended to use it. + A library is provided to take care of it, see lz4frame.h. +*/ + +/*^*************************************************************** +* Export parameters +*****************************************************************/ +/* +* LZ4_DLL_EXPORT : +* Enable exporting of functions when building a Windows DLL +* LZ4LIB_API : +* Control library symbols visibility. +*/ +#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) +# define LZ4LIB_API __declspec(dllexport) +#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) +# define LZ4LIB_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#elif defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4LIB_API __attribute__ ((__visibility__ ("default"))) +#else +# define LZ4LIB_API +#endif + + +/*------ Version ------*/ +#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ +#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 6 /* for tweaks, bug-fixes, or development */ + +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) + +#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE +#define LZ4_QUOTE(str) #str +#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) +#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) + +LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; to be used when checking dll version */ +LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; to be used when checking dll version */ + + +/*-************************************ +* Tuning parameter +**************************************/ +/*! + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage can improve speed, due to cache effect + * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + */ +#ifndef LZ4_MEMORY_USAGE +# define LZ4_MEMORY_USAGE 14 +#endif + +/*-************************************ +* Simple Functions +**************************************/ +/*! LZ4_compress_default() : + Compresses 'sourceSize' bytes from buffer 'source' + into already allocated 'dest' buffer of size 'maxDestSize'. + Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). + It also runs faster, so it's a recommended setting. + If the function cannot compress 'source' into a more limited 'dest' budget, + compression stops *immediately*, and the function result is zero. + As a consequence, 'dest' content is not valid. + This function never writes outside 'dest' buffer, nor read outside 'source' buffer. + sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) + return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) + or 0 if compression fails */ +LZ4LIB_API int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); + +/*! LZ4_decompress_safe() : + compressedSize : is the precise full size of the compressed block. + maxDecompressedSize : is the size of destination buffer, which must be already allocated. + return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) + If destination buffer is not large enough, decoding will stop and output an error code (<0). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against buffer overflow exploits, including malicious data packets. + It never writes outside output buffer, nor reads outside input buffer. +*/ +LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); + + +/*-************************************ +* Advanced Functions +**************************************/ +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) + +/*! +LZ4_compressBound() : + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (destination buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) + inputSize : max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) +*/ +LZ4LIB_API int LZ4_compressBound(int inputSize); + +/*! +LZ4_compress_fast() : + Same as LZ4_compress_default(), but allows to select an "acceleration" factor. + The larger the acceleration value, the faster the algorithm, but also the lesser the compression. + It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. + An acceleration value of "1" is the same as regular LZ4_compress_default() + Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. +*/ +LZ4LIB_API int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); + + +/*! +LZ4_compress_fast_extState() : + Same compression function, just using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and allocate it on 8-bytes boundaries (using malloc() typically). + Then, provide it as 'void* state' to compression function. +*/ +LZ4LIB_API int LZ4_sizeofState(void); +LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); + + +/*! +LZ4_compress_destSize() : + Reverse the logic, by compressing as much data as possible from 'source' buffer + into already allocated buffer 'dest' of size 'targetDestSize'. + This function either compresses the entire 'source' content into 'dest' if it's large enough, + or fill 'dest' buffer completely with as much data as possible from 'source'. + *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. + New value is necessarily <= old value. + return : Nb bytes written into 'dest' (necessarily <= targetDestSize) + or 0 if compression fails +*/ +LZ4LIB_API int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); + + +/*! +LZ4_decompress_fast() : + originalSize : is the original and therefore uncompressed size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is detected malformed, the function will stop decoding and return a negative result. + Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. + note : This function fully respect memory boundaries for properly formed compressed data. + It is a bit faster than LZ4_decompress_safe(). + However, it does not provide any protection against intentionally modified data stream (malicious input). + Use this function in trusted environment only (data to decode comes from a trusted source). +*/ +LZ4LIB_API int LZ4_decompress_fast (const char* source, char* dest, int originalSize); + +/*! +LZ4_decompress_safe_partial() : + This function decompress a compressed block of size 'compressedSize' at position 'source' + into destination buffer 'dest' of size 'maxDecompressedSize'. + The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, + reducing decompression time. + return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) + Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. + Always control how many bytes were decoded. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets +*/ +LZ4LIB_API int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); + + +/*-********************************************* +* Streaming Compression Functions +***********************************************/ +typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ + +/*! LZ4_createStream() and LZ4_freeStream() : + * LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. + * LZ4_freeStream() releases its memory. + */ +LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); +LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr); + +/*! LZ4_resetStream() : + * An LZ4_stream_t structure can be allocated once and re-used multiple times. + * Use this function to init an allocated `LZ4_stream_t` structure and start a new compression. + */ +LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); + +/*! LZ4_loadDict() : + * Use this function to load a static dictionary into LZ4_stream. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed. + * Return : dictionary size, in bytes (necessarily <= 64 KB) + */ +LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); + +/*! LZ4_compress_fast_continue() : + * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio. + * Important : Previous data blocks are assumed to remain present and unmodified ! + * 'dst' buffer must be already allocated. + * If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. + * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. + * After an error, the stream status is invalid, and it can only be reset or freed. + */ +LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_saveDict() : + * If previously compressed data block is not guaranteed to remain available at its current memory location, + * save it into a safer place (char* safeBuffer). + * Note : it's not necessary to call LZ4_loadDict() after LZ4_saveDict(), dictionary is immediately usable. + * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. + */ +LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize); + + +/*-********************************************** +* Streaming Decompression Functions +* Bufferless synchronous API +************************************************/ +typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* incomplete type (defined later) */ + +/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() : + * creation / destruction of streaming decompression tracking structure */ +LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); +LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); + +/*! LZ4_setStreamDecode() : + * Use this function to instruct where to find the dictionary. + * Setting a size of 0 is allowed (same effect as reset). + * @return : 1 if OK, 0 if error + */ +LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); + +/*! +LZ4_decompress_*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) + In the case of a ring buffers, decoding buffer must be either : + - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) + In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). + - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. + maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including small ones ( < 64 KB). + - _At least_ 64 KB + 8 bytes + maxBlockSize. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including larger than decoding buffer. + Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, + and indicate where it is saved using LZ4_setStreamDecode() +*/ +LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); +LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); + + +/*! LZ4_decompress_*_usingDict() : + * These decoding functions work the same as + * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue() + * They are stand-alone, and don't need an LZ4_streamDecode_t structure. + */ +LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); +LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); + + +/*^********************************************** + * !!!!!! STATIC LINKING ONLY !!!!!! + ***********************************************/ +/*-************************************ + * Private definitions + ************************************** + * Do not use these definitions. + * They are exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. + * Using these definitions will expose code to API and/or ABI break in future versions of the library. + **************************************/ +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) +#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ + +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) + +typedef struct { + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint32_t initCheck; + const uint8_t* dictionary; + uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ + uint32_t dictSize; +} LZ4_stream_t_internal; + +typedef struct { + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#else + +typedef struct { + unsigned int hashTable[LZ4_HASH_SIZE_U32]; + unsigned int currentOffset; + unsigned int initCheck; + const unsigned char* dictionary; + unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */ + unsigned int dictSize; +} LZ4_stream_t_internal; + +typedef struct { + const unsigned char* externalDict; + size_t extDictSize; + const unsigned char* prefixEnd; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#endif + +/*! + * LZ4_stream_t : + * information structure to track an LZ4 stream. + * init this structure before first use. + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * and may change in a future version ! + */ +#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) +union LZ4_stream_u { + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_stream_t */ + + +/*! + * LZ4_streamDecode_t : + * information structure to track an LZ4 stream during decompression. + * init this structure using LZ4_setStreamDecode (or memset()) before first use + * note : only use in association with static linking ! + * this definition is not API/ABI safe, + * and may change in a future version ! + */ +#define LZ4_STREAMDECODESIZE_U64 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +union LZ4_streamDecode_u { + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_streamDecode_t */ + + +/*-************************************ +* Obsolete Functions +**************************************/ + +/*! Deprecation warnings + Should deprecation warnings be a problem, + it is generally possible to disable them, + typically with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual. + Otherwise, it's also possible to define LZ4_DISABLE_DEPRECATE_WARNINGS */ +#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS +# define LZ4_DEPRECATED(message) /* disable deprecation warnings */ +#else +# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define LZ4_DEPRECATED(message) [[deprecated(message)]] +# elif (LZ4_GCC_VERSION >= 405) || defined(__clang__) +# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (LZ4_GCC_VERSION >= 301) +# define LZ4_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define LZ4_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") +# define LZ4_DEPRECATED(message) +# endif +#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ + +/* Obsolete compression functions */ +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_default() instead") int LZ4_compress (const char* source, char* dest, int sourceSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_default() instead") int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* Obsolete decompression functions */ +LZ4LIB_API LZ4_DEPRECATED("use LZ4_decompress_fast() instead") int LZ4_uncompress (const char* source, char* dest, int outputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_decompress_safe() instead") int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); + +/* Obsolete streaming functions; use new streaming interface whenever possible */ +LZ4LIB_API LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state); + +/* Obsolete streaming decoding functions */ +LZ4LIB_API LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); + +#endif /* LZ4_H_2983827168210 */ + +#if defined (__cplusplus) +} +#endif +/* + LZ4 - Fast LZ compression algorithm + Copyright (C) 2011-2017, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 +*/ + + +/*-************************************ +* Tuning parameters +**************************************/ +/* + * HEAPMODE : + * Select how default compression functions will allocate memory for their hash table, + * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()). + */ +#ifndef HEAPMODE +# define HEAPMODE 0 +#endif + +/* + * ACCELERATION_DEFAULT : + * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 + */ +#define ACCELERATION_DEFAULT 1 + + +/*-************************************ +* CPU Feature Detection +**************************************/ +/* LZ4_FORCE_MEMORY_ACCESS + * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. + * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. + * The below switch allow to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets which assembly generation depends on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define LZ4_FORCE_MEMORY_ACCESS 2 +# elif defined(__INTEL_COMPILER) || defined(__GNUC__) +# define LZ4_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +/* + * LZ4_FORCE_SW_BITCOUNT + * Define this parameter if your target system or compiler does not support hardware bit count + */ +#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ +# define LZ4_FORCE_SW_BITCOUNT +#endif + + +/*-************************************ +* Dependency +**************************************/ +/* see also "memory routines" below */ + + +/*-************************************ +* Compiler Options +**************************************/ +#ifdef _MSC_VER /* Visual Studio */ +# define FORCE_INLINE static __forceinline +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ +#else +# if defined(__GNUC__) || defined(__clang__) +# define FORCE_INLINE static inline __attribute__((always_inline)) +# elif defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define FORCE_INLINE static inline +# else +# define FORCE_INLINE static +# endif +#endif /* _MSC_VER */ + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) +# define expect(expr,value) (__builtin_expect ((expr),(value)) ) +#else +# define expect(expr,value) (expr) +#endif + +#define likely(expr) expect((expr) != 0, 1) +#define unlikely(expr) expect((expr) != 0, 0) + + +/*-************************************ +* Memory routines +**************************************/ +#define ALLOCATOR(n,s) calloc(n,s) +#define FREEMEM free +#define MEM_INIT memset + + +/*-************************************ +* Basic Types +**************************************/ +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) + typedef uint8_t BYTE; + typedef uint16_t U16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; + typedef uintptr_t uptrval; +#else + typedef unsigned char BYTE; + typedef unsigned short U16; + typedef unsigned int U32; + typedef signed int S32; + typedef unsigned long long U64; + typedef size_t uptrval; /* generally true, except OpenVMS-64 */ +#endif + +#if defined(__x86_64__) + typedef U64 reg_t; /* 64-bits in x32 mode */ +#else + typedef size_t reg_t; /* 32-bits in x32 mode */ +#endif + +/*-************************************ +* Reading and writing into memory +**************************************/ +static unsigned LZ4_isLittleEndian(void) +{ + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +} + + +#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) +/* lie to the compiler about data alignment; use with caution */ + +static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; } +static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; } +static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; } + +static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } + +#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign; + +static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } +static U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } +static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; } + +static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } +static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } + +#else /* safe and portable access through memcpy() */ + +static U16 LZ4_read16(const void* memPtr) +{ + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static U32 LZ4_read32(const void* memPtr) +{ + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static reg_t LZ4_read_ARCH(const void* memPtr) +{ + reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +static void LZ4_write16(void* memPtr, U16 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +static void LZ4_write32(void* memPtr, U32 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +#endif /* LZ4_FORCE_MEMORY_ACCESS */ + + +static U16 LZ4_readLE16(const void* memPtr) +{ + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } +} + +static void LZ4_writeLE16(void* memPtr, U16 value) +{ + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } +} + +static void LZ4_copy8(void* dst, const void* src) +{ + memcpy(dst,src,8); +} + +/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ +static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) +{ + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; + + do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e); +} + + +/*-************************************ +* Common Constants +**************************************/ +#define MINMATCH 4 + +#define WILDCOPYLENGTH 8 +#define LASTLITERALS 5 +#define MFLIMIT (WILDCOPYLENGTH+MINMATCH) +static const int LZ4_minLength = (MFLIMIT+1); + +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define MAXD_LOG 16 +#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) + +#define ML_BITS 4 +#define ML_MASK ((1U<<ML_BITS)-1) +#define RUN_BITS (8-ML_BITS) +#define RUN_MASK ((1U<<RUN_BITS)-1) + + +/*-************************************ +* Common Utils +**************************************/ +#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ + + +/*-************************************ +* Common functions +**************************************/ +static unsigned LZ4_NbCommonBytes (register reg_t val) +{ + if (LZ4_isLittleEndian()) { + if (sizeof(val)==8) { +# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (int)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll((U64)val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } else /* 32 bits */ { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward( &r, (U32)val ); + return (int)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz((U32)val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { +# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll((U64)val) >> 3); +# else + unsigned r; + if (!(val>>32)) { r=4; } else { r=0; val>>=32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif + } else /* 32 bits */ { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); +# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz((U32)val) >> 3); +# else + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif + } + } +} + +#define STEPSIZE sizeof(reg_t) +static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) +{ + const BYTE* const pStart = pIn; + + while (likely(pIn<pInLimit-(STEPSIZE-1))) { + reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); + if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; } + pIn += LZ4_NbCommonBytes(diff); + return (unsigned)(pIn - pStart); + } + + if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; } + if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; } + if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++; + return (unsigned)(pIn - pStart); +} + + +#ifndef LZ4_COMMONDEFS_ONLY +/*-************************************ +* Local Constants +**************************************/ +static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1)); +static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */ + + +/*-************************************ +* Local Structures and types +**************************************/ +typedef enum { + noLimit = 0,notLimited = 0, + limitedOutput = 1, + limitedDestSize = 2, +} limitedOutput_directive; +typedef enum { byPtr, byU32, byU16 } tableType_t; + +typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; +typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; + +typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; +typedef enum { full = 0, partial = 1 } earlyEnd_directive; + + +/*-************************************ +* Local Utils +**************************************/ +int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } +int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } +int LZ4_sizeofState() { return LZ4_STREAMSIZE; } + + +/*-****************************** +* Compression functions +********************************/ +static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) +{ + if (tableType == byU16) + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); +} + +static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) +{ + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + else + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); +} + +FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) +{ + if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + return LZ4_hash4(LZ4_read32(p), tableType); +} + +static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) +{ + switch (tableType) + { + case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } + } +} + +FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); +} + +static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } + if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } + { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ +} + +FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); +} + + +/** LZ4_compress_generic() : + inlined, to ensure branches are decided at compilation time */ +FORCE_INLINE int LZ4_compress_generic( + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dict, + const dictIssue_directive dictIssue, + const U32 acceleration) +{ + const BYTE* ip = (const BYTE*) source; + const BYTE* base; + const BYTE* lowLimit; + const BYTE* const lowRefLimit = ip - cctx->dictSize; + const BYTE* const dictionary = cctx->dictionary; + const BYTE* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* anchor = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dest; + BYTE* const olimit = op + maxOutputSize; + + U32 forwardH; + + /* Init conditions */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */ + switch(dict) + { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source - cctx->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ + + /* First Byte */ + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + ptrdiff_t refDelta = 0; + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + + } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) + || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } + + /* Encode Literals */ + { unsigned const litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && /* Check output buffer overflow */ + (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; + if (litLength >= RUN_MASK) { + int len = (int)litLength-RUN_MASK; + *token = (RUN_MASK<<ML_BITS); + for(; len >= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength<<ML_BITS); + + /* Copy Literals */ + LZ4_wildCopy(op, anchor, op+litLength); + op+=litLength; + } + +_next_match: + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip-match)); op+=2; + + /* Encode MatchLength */ + { unsigned matchCode; + + if ((dict==usingExtDict) && (lowLimit==dictionary)) { + const BYTE* limit; + match += refDelta; + limit = ip + (dictEnd-match); + if (limit > matchlimit) limit = matchlimit; + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip==limit) { + unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + } + + if ( outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) + return 0; + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255; + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else + *token += (BYTE)(matchCode); + } + + anchor = ip; + + /* Test end of chunk */ + if (ip > mflimit) break; + + /* Fill table */ + LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + if (dict==usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } } + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) + && (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } + +_last_literals: + /* Encode Last Literals */ + { size_t const lastRun = (size_t)(iend - anchor); + if ( (outputLimited) && /* Check output buffer overflow */ + ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) + return 0; + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRun<<ML_BITS); + } + memcpy(op, anchor, lastRun); + op += lastRun; + } + + /* End */ + return (int) (((char*)op)-dest); +} + + +int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + LZ4_resetStream((LZ4_stream_t*)state); + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } else { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } +} + + +int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ +#if (HEAPMODE) + void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ +#else + LZ4_stream_t ctx; + void* const ctxPtr = &ctx; +#endif + + int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + +#if (HEAPMODE) + FREEMEM(ctxPtr); +#endif + return result; +} + + +int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); +} + + +/* hidden debug function */ +/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ +int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + LZ4_stream_t ctx; + LZ4_resetStream(&ctx); + + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration); +} + + +/*-****************************** +* *_destSize() variant +********************************/ + +static int LZ4_compress_destSize_generic( + LZ4_stream_t_internal* const ctx, + const char* const src, + char* const dst, + int* const srcSizePtr, + const int targetDstSize, + const tableType_t tableType) +{ + const BYTE* ip = (const BYTE*) src; + const BYTE* base = (const BYTE*) src; + const BYTE* lowLimit = (const BYTE*) src; + const BYTE* anchor = ip; + const BYTE* const iend = ip + *srcSizePtr; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dst; + BYTE* const oend = op + targetDstSize; + BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; + BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); + BYTE* const oMaxSeq = oMaxLit - 1 /* token */; + + U32 forwardH; + + + /* Init conditions */ + if (targetDstSize < 1) return 0; /* Impossible to store anything */ + if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (*srcSizePtr<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ + + /* First Byte */ + *srcSizePtr = 0; + LZ4_putPosition(ip, ctx->hashTable, tableType, base); + ip++; forwardH = LZ4_hashPosition(ip, tableType); + + /* Main Loop */ + for ( ; ; ) { + const BYTE* match; + BYTE* token; + + /* Find a match */ + { const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = 1 << LZ4_skipTrigger; + + do { + U32 h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base); + + } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + /* Encode Literal length */ + { unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if (op + ((litLength+240)/255) + litLength > oMaxLit) { + /* Not enough space for a last match */ + op--; + goto _last_literals; + } + if (litLength>=RUN_MASK) { + unsigned len = litLength - RUN_MASK; + *token=(RUN_MASK<<ML_BITS); + for(; len >= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength<<ML_BITS); + + /* Copy Literals */ + LZ4_wildCopy(op, anchor, op+litLength); + op += litLength; + } + +_next_match: + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip-match)); op+=2; + + /* Encode MatchLength */ + { size_t matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + + if (op + ((matchLength+240)/255) > oMaxMatch) { + /* Match description too long : reduce it */ + matchLength = (15-1) + (oMaxMatch-op) * 255; + } + ip += MINMATCH + matchLength; + + if (matchLength>=ML_MASK) { + *token += ML_MASK; + matchLength -= ML_MASK; + while (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } + + anchor = ip; + + /* Test end of block */ + if (ip > mflimit) break; + if (op > oMaxSeq) break; + + /* Fill table */ + LZ4_putPosition(ip-2, ctx->hashTable, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, ctx->hashTable, tableType, base); + LZ4_putPosition(ip, ctx->hashTable, tableType, base); + if ( (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } + +_last_literals: + /* Encode Last Literals */ + { size_t lastRunSize = (size_t)(iend - anchor); + if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) { + /* adapt lastRunSize to fill 'dst' */ + lastRunSize = (oend-op) - 1; + lastRunSize -= (lastRunSize+240)/255; + } + ip = anchor + lastRunSize; + + if (lastRunSize >= RUN_MASK) { + size_t accumulator = lastRunSize - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRunSize<<ML_BITS); + } + memcpy(op, anchor, lastRunSize); + op += lastRunSize; + } + + /* End */ + *srcSizePtr = (int) (((const char*)ip)-src); + return (int) (((char*)op)-dst); +} + + +static int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize) +{ + LZ4_resetStream(state); + + if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ + return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); + } else { + if (*srcSizePtr < LZ4_64Klimit) + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16); + else + return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, sizeof(void*)==8 ? byU32 : byPtr); + } +} + + +int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) +{ +#if (HEAPMODE) + LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ +#else + LZ4_stream_t ctxBody; + LZ4_stream_t* ctx = &ctxBody; +#endif + + int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); + +#if (HEAPMODE) + FREEMEM(ctx); +#endif + return result; +} + + + +/*-****************************** +* Streaming functions +********************************/ + +LZ4_stream_t* LZ4_createStream(void) +{ + LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); + LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + LZ4_resetStream(lz4s); + return lz4s; +} + +void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +{ + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); +} + +int LZ4_freeStream (LZ4_stream_t* LZ4_stream) +{ + FREEMEM(LZ4_stream); + return (0); +} + + +#define HASH_UNIT sizeof(reg_t) +int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) +{ + LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse; + const BYTE* p = (const BYTE*)dictionary; + const BYTE* const dictEnd = p + dictSize; + const BYTE* base; + + if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ + LZ4_resetStream(LZ4_dict); + + if (dictSize < (int)HASH_UNIT) { + dict->dictionary = NULL; + dict->dictSize = 0; + return 0; + } + + if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; + dict->currentOffset += 64 KB; + base = p - dict->currentOffset; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->currentOffset += dict->dictSize; + + while (p <= dictEnd-HASH_UNIT) { + LZ4_putPosition(p, dict->hashTable, byU32, base); + p+=3; + } + + return dict->dictSize; +} + + +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) +{ + if ((LZ4_dict->currentOffset > 0x80000000) || + ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */ + /* rescale hash table */ + U32 const delta = LZ4_dict->currentOffset - 64 KB; + const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + int i; + for (i=0; i<LZ4_HASH_SIZE_U32; i++) { + if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0; + else LZ4_dict->hashTable[i] -= delta; + } + LZ4_dict->currentOffset = 64 KB; + if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; + LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; + } +} + + +int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + const BYTE* smallest = (const BYTE*) source; + if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ + if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; + LZ4_renormDictT(streamPtr, smallest); + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + + /* Check overlapping input/dictionary space */ + { const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { + streamPtr->dictSize = (U32)(dictEnd - sourceEnd); + if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; + if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; + streamPtr->dictionary = dictEnd - streamPtr->dictSize; + } + } + + /* prefix mode : source data follows dictionary */ + if (dictEnd == (const BYTE*)source) { + int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); + else + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); + streamPtr->dictSize += (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } + + /* external dictionary mode */ + { int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); + else + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } +} + + +/* Hidden debug function, to force external dictionary mode */ +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) +{ + LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse; + int result; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + + const BYTE* smallest = dictEnd; + if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; + LZ4_renormDictT(streamPtr, smallest); + + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + + return result; +} + + +/*! LZ4_saveDict() : + * If previously compressed data block is not guaranteed to remain available at its memory location, + * save it into a safer place (char* safeBuffer). + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue(). + * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. + */ +int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) +{ + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + + if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + + memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + + dict->dictionary = (const BYTE*)safeBuffer; + dict->dictSize = (U32)dictSize; + + return dictSize; +} + + + +/*-***************************** +* Decompression functions +*******************************/ +/*! LZ4_decompress_generic() : + * This generic decompression function cover all use cases. + * It shall be instantiated several times, using different sets of directives + * Note that it is important this generic function is really inlined, + * in order to remove useless branches during compilation optimization. + */ +FORCE_INLINE int LZ4_decompress_generic( + const char* const source, + char* const dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* == dest when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ + ) +{ + /* Local Variables */ + const BYTE* ip = (const BYTE*) source; + const BYTE* const iend = ip + inputSize; + + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = lowPrefix - dictSize; + + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; + const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; + + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + + + /* Special cases */ + if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ + if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; + + /* get literal length */ + unsigned const token = *ip++; + if ((length=(token>>ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) & (s==255) ); + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error; /* overflow detection */ + if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error; /* overflow detection */ + } + + /* copy literals */ + cpy = op+length; + if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) + || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) + { + if (partialDecoding) { + if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ + } else { + if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; op = cpy; + + /* get offset */ + offset = LZ4_readLE16(ip); ip+=2; + match = op - offset; + if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */ + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; + length += s; + } while (s==255); + if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + + /* check external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ + + if (length <= (size_t)(lowPrefix-match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix-match); + size_t const restSize = length - copySize; + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) *op++ = *copyFrom++; + } else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } } + continue; + } + + /* copy match within block */ + cpy = op + length; + if (unlikely(offset<8)) { + const int dec64 = dec64table[offset]; + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += dec32table[offset]; + memcpy(op+4, match, 4); + match -= dec64; + } else { LZ4_copy8(op, match); match+=8; } + op += 8; + + if (unlikely(cpy>oend-12)) { + BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op<cpy) *op++ = *match++; + } else { + LZ4_copy8(op, match); + if (length>16) LZ4_wildCopy(op+8, match+8, cpy); + } + op=cpy; /* correction */ + } + + /* end of decoding */ + if (endOnInput) + return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ + else + return (int) (((const char*)ip)-source); /* Nb of input bytes read */ + + /* Overflow error detected */ +_output_error: + return (int) (-(((const char*)ip)-source))-1; +} + + +int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); +} + +int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0); +} + +int LZ4_decompress_fast(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB); +} + + +/*===== streaming decompression functions =====*/ + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStreamDecode() + * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure. + */ +LZ4_streamDecode_t* LZ4_createStreamDecode(void) +{ + LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t)); + return lz4s; +} + +int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) +{ + FREEMEM(LZ4_stream); + return 0; +} + +/*! + * LZ4_setStreamDecode() : + * Use this function to instruct where to find the dictionary. + * This function is not necessary if previous data is still available where it was decoded. + * Loading a size of 0 is allowed (same effect as no dictionary). + * Return : 1 if OK, 0 if error + */ +int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + lz4sd->prefixSize = (size_t) dictSize; + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->externalDict = NULL; + lz4sd->extDictSize = 0; + return 1; +} + +/* +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setStreamDecode() +*/ +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += result; + lz4sd->prefixEnd += result; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = result; + lz4sd->prefixEnd = (BYTE*)dest + result; + } + + return result; +} + +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +{ + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) { + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += originalSize; + lz4sd->prefixEnd += originalSize; + } else { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = originalSize; + lz4sd->prefixEnd = (BYTE*)dest + originalSize; + } + + return result; +} + + +/* +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters +*/ + +FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); + if (dictStart+dictSize == dest) { + if (dictSize >= (int)(64 KB - 1)) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); + } + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + +int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); +} + +int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); +} + +/* debug function */ +int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + + +/*=************************************************* +* Obsolete Functions +***************************************************/ +/* obsolete compression functions */ +int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } +int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); } +int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } +int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); } +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); } + +/* +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is totally equivalent to LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe +*/ +int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + + +/* Obsolete Streaming functions */ + +int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } + +static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base) +{ + MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t)); + lz4ds->internal_donotuse.bufferStart = base; +} + +int LZ4_resetStreamState(void* state, char* inputBuffer) +{ + if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ + LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer); + return 0; +} + +void* LZ4_create (char* inputBuffer) +{ + LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t)); + LZ4_init (lz4ds, (BYTE*)inputBuffer); + return lz4ds; +} + +char* LZ4_slideInputBuffer (void* LZ4_Data) +{ + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse; + int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); + return (char*)(ctx->bufferStart + dictSize); +} + +/* Obsolete streaming decompression functions */ + +int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +#endif /* LZ4_COMMONDEFS_ONLY */ +/* + LZ4 HC - High Compression Mode of LZ4 + Header File + Copyright (C) 2011-2017, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +#ifndef LZ4_HC_H_19834876238432 +#define LZ4_HC_H_19834876238432 + +#if defined (__cplusplus) +extern "C" { +#endif + +/* --- Dependency --- */ +/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */ + + +/* --- Useful constants --- */ +#define LZ4HC_CLEVEL_MIN 3 +#define LZ4HC_CLEVEL_DEFAULT 9 +#define LZ4HC_CLEVEL_OPT_MIN 11 +#define LZ4HC_CLEVEL_MAX 12 + + +/*-************************************ + * Block Compression + **************************************/ +/*! LZ4_compress_HC() : + * Compress data from `src` into `dst`, using the more powerful but slower "HC" algorithm. + * `dst` must be already allocated. + * Compression is guaranteed to succeed if `dstCapacity >= LZ4_compressBound(srcSize)` (see "lz4.h") + * Max supported `srcSize` value is LZ4_MAX_INPUT_SIZE (see "lz4.h") + * `compressionLevel` : Recommended values are between 4 and 9, although any value between 1 and LZ4HC_MAX_CLEVEL will work. + * Values >LZ4HC_MAX_CLEVEL behave the same as LZ4HC_MAX_CLEVEL. + * @return : the number of bytes written into 'dst' + * or 0 if compression fails. + */ +LZ4LIB_API int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel); + + +/* Note : + * Decompression functions are provided within "lz4.h" (BSD license) + */ + + +/*! LZ4_compress_HC_extStateHC() : + * Same as LZ4_compress_HC(), but using an externally allocated memory segment for `state`. + * `state` size is provided by LZ4_sizeofStateHC(). + * Memory segment must be aligned on 8-bytes boundaries (which a normal malloc() will do properly). + */ +LZ4LIB_API int LZ4_compress_HC_extStateHC(void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel); +LZ4LIB_API int LZ4_sizeofStateHC(void); + + +/*-************************************ + * Streaming Compression + * Bufferless synchronous API + **************************************/ + typedef union LZ4_streamHC_u LZ4_streamHC_t; /* incomplete type (defined later) */ + +/*! LZ4_createStreamHC() and LZ4_freeStreamHC() : + * These functions create and release memory for LZ4 HC streaming state. + * Newly created states are automatically initialized. + * Existing states can be re-used several times, using LZ4_resetStreamHC(). + * These methods are API and ABI stable, they can be used in combination with a DLL. + */ +LZ4LIB_API LZ4_streamHC_t* LZ4_createStreamHC(void); +LZ4LIB_API int LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr); + +LZ4LIB_API void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel); +LZ4LIB_API int LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize); + +LZ4LIB_API int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr, const char* src, char* dst, int srcSize, int maxDstSize); + +LZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize); + +/* + These functions compress data in successive blocks of any size, using previous blocks as dictionary. + One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks. + There is an exception for ring buffers, which can be smaller than 64 KB. + Ring buffers scenario is automatically detected and handled by LZ4_compress_HC_continue(). + + Before starting compression, state must be properly initialized, using LZ4_resetStreamHC(). + A first "fictional block" can then be designated as initial dictionary, using LZ4_loadDictHC() (Optional). + + Then, use LZ4_compress_HC_continue() to compress each successive block. + Previous memory blocks (including initial dictionary when present) must remain accessible and unmodified during compression. + 'dst' buffer should be sized to handle worst case scenarios (see LZ4_compressBound()), to ensure operation success. + Because in case of failure, the API does not guarantee context recovery, and context will have to be reset. + If `dst` buffer budget cannot be >= LZ4_compressBound(), consider using LZ4_compress_HC_continue_destSize() instead. + + If, for any reason, previous data block can't be preserved unmodified in memory for next compression block, + you can save it to a more stable memory space, using LZ4_saveDictHC(). + Return value of LZ4_saveDictHC() is the size of dictionary effectively saved into 'safeBuffer'. +*/ + + + /*-************************************* + * PRIVATE DEFINITIONS : + * Do not use these definitions. + * They are exposed to allow static allocation of `LZ4_streamHC_t`. + * Using these definitions makes the code vulnerable to potential API break when upgrading LZ4 + **************************************/ +#define LZ4HC_DICTIONARY_LOGSIZE 17 /* because of btopt, hc would only need 16 */ +#define LZ4HC_MAXD (1<<LZ4HC_DICTIONARY_LOGSIZE) +#define LZ4HC_MAXD_MASK (LZ4HC_MAXD - 1) + +#define LZ4HC_HASH_LOG 15 +#define LZ4HC_HASHTABLESIZE (1 << LZ4HC_HASH_LOG) +#define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1) + + +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) + +typedef struct +{ + uint32_t hashTable[LZ4HC_HASHTABLESIZE]; + uint16_t chainTable[LZ4HC_MAXD]; + const uint8_t* end; /* next block here to continue on current prefix */ + const uint8_t* base; /* All index relative to this position */ + const uint8_t* dictBase; /* alternate base for extDict */ + uint8_t* inputBuffer; /* deprecated */ + uint32_t dictLimit; /* below that point, need extDict */ + uint32_t lowLimit; /* below that point, no more dict */ + uint32_t nextToUpdate; /* index from which to continue dictionary update */ + uint32_t searchNum; /* only for optimal parser */ + uint32_t compressionLevel; +} LZ4HC_CCtx_internal; + +#else + +typedef struct +{ + unsigned int hashTable[LZ4HC_HASHTABLESIZE]; + unsigned short chainTable[LZ4HC_MAXD]; + const unsigned char* end; /* next block here to continue on current prefix */ + const unsigned char* base; /* All index relative to this position */ + const unsigned char* dictBase; /* alternate base for extDict */ + unsigned char* inputBuffer; /* deprecated */ + unsigned int dictLimit; /* below that point, need extDict */ + unsigned int lowLimit; /* below that point, no more dict */ + unsigned int nextToUpdate; /* index from which to continue dictionary update */ + unsigned int searchNum; /* only for optimal parser */ + int compressionLevel; +} LZ4HC_CCtx_internal; + +#endif + +#define LZ4_STREAMHCSIZE (4*LZ4HC_HASHTABLESIZE + 2*LZ4HC_MAXD + 56) /* 393268 */ +#define LZ4_STREAMHCSIZE_SIZET (LZ4_STREAMHCSIZE / sizeof(size_t)) +union LZ4_streamHC_u { + size_t table[LZ4_STREAMHCSIZE_SIZET]; + LZ4HC_CCtx_internal internal_donotuse; +}; /* previously typedef'd to LZ4_streamHC_t */ +/* + LZ4_streamHC_t : + This structure allows static allocation of LZ4 HC streaming state. + State must be initialized using LZ4_resetStreamHC() before first use. + + Static allocation shall only be used in combination with static linking. + When invoking LZ4 from a DLL, use create/free functions instead, which are API and ABI stable. +*/ + + +/*-************************************ +* Deprecated Functions +**************************************/ +/* see lz4.h LZ4_DISABLE_DEPRECATE_WARNINGS to turn off deprecation warnings */ + +/* deprecated compression functions */ +/* these functions will trigger warning messages in future releases */ +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC (const char* source, char* dest, int inputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* Deprecated Streaming functions using older model; should no longer be used */ +LZ4LIB_API LZ4_DEPRECATED("use LZ4_createStreamHC() instead") void* LZ4_createHC (char* inputBuffer); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_saveDictHC() instead") char* LZ4_slideInputBufferHC (void* LZ4HC_Data); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_freeStreamHC() instead") int LZ4_freeHC (void* LZ4HC_Data); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_createStreamHC() instead") int LZ4_sizeofStreamStateHC(void); +LZ4LIB_API LZ4_DEPRECATED("use LZ4_resetStreamHC() instead") int LZ4_resetStreamStateHC(void* state, char* inputBuffer); + + +#if defined (__cplusplus) +} +#endif + +#endif /* LZ4_HC_H_19834876238432 */ + +/*-************************************************ + * !!!!! STATIC LINKING ONLY !!!!! + * Following definitions are considered experimental. + * They should not be linked from DLL, + * as there is no guarantee of API stability yet. + * Prototypes will be promoted to "stable" status + * after successfull usage in real-life scenarios. + *************************************************/ +#ifdef LZ4_HC_STATIC_LINKING_ONLY /* protection macro */ +#ifndef LZ4_HC_SLO_098092834 +#define LZ4_HC_SLO_098092834 + +/*! LZ4_compress_HC_destSize() : + * Will try to compress as much data from `src` as possible + * that can fit in `targetDstSize` budget. + * Result is provided in 2 parts : + * @return : the number of bytes written into 'dst' + * or 0 if compression fails. + * `srcSizePtr` : value will be updated to indicate how much bytes were read from `src` + */ +LZ4LIB_API int LZ4_compress_HC_destSize(void* LZ4HC_Data, + const char* src, char* dst, + int* srcSizePtr, int targetDstSize, + int compressionLevel); + +/*! LZ4_compress_HC_continue_destSize() : + * Similar as LZ4_compress_HC_continue(), + * but will read a variable nb of bytes from `src` + * to fit into `targetDstSize` budget. + * Result is provided in 2 parts : + * @return : the number of bytes written into 'dst' + * or 0 if compression fails. + * `srcSizePtr` : value will be updated to indicate how much bytes were read from `src` + * Important : due to limitations, this prototype only works well up to cLevel < LZ4HC_CLEVEL_OPT_MIN + * beyond that level, compression performance will be much reduced due to internal incompatibilities + */ +LZ4LIB_API int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t* LZ4_streamHCPtr, + const char* src, char* dst, + int* srcSizePtr, int targetDstSize); + +#endif /* LZ4_HC_SLO_098092834 */ +#endif /* LZ4_HC_STATIC_LINKING_ONLY */ +/* + lz4opt.h - Optimal Mode of LZ4 + Copyright (C) 2015-2017, Przemyslaw Skibinski <inikep@gmail.com> + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ + +#define LZ4_OPT_NUM (1<<12) + + +typedef struct { + int off; + int len; +} LZ4HC_match_t; + +typedef struct { + int price; + int off; + int mlen; + int litlen; +} LZ4HC_optimal_t; + + +/* price in bits */ +FORCE_INLINE size_t LZ4HC_literalsPrice(size_t litlen) +{ + size_t price = litlen; + if (litlen >= (size_t)RUN_MASK) price += 1 + (litlen-RUN_MASK)/255; + return price; +} + + +/* requires mlen >= MINMATCH */ +FORCE_INLINE size_t LZ4HC_sequencePrice(size_t litlen, size_t mlen) +{ + size_t price = 2 + 1; /* 16-bit offset + token */ + + price += LZ4HC_literalsPrice(litlen); + + if (mlen >= (size_t)(ML_MASK+MINMATCH)) + price+= 1+(mlen-(ML_MASK+MINMATCH))/255; + + return price; +} + + +/*=== Common LZ4 definitions ===*/ +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wunused-function" +#endif +#if defined (__clang__) +# pragma clang diagnostic ignored "-Wunused-function" +#endif + +//#define LZ4_COMMONDEFS_ONLY + + +/*=== Constants ===*/ +#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH) + + +/*=== Macros ===*/ +#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG)) +#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */ +#define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */ +static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); } +/*-************************************* +* Binary Tree search +***************************************/ +FORCE_INLINE int LZ4HC_BinTree_InsertAndGetAllMatches ( + LZ4HC_CCtx_internal* ctx, + const BYTE* const ip, + const BYTE* const iHighLimit, + size_t best_mlen, + LZ4HC_match_t* matches, + int* matchNum) +{ + U16* const chainTable = ctx->chainTable; + U32* const HashTable = ctx->hashTable; + const BYTE* const base = ctx->base; + const U32 dictLimit = ctx->dictLimit; + const U32 current = (U32)(ip - base); + const U32 lowLimit = (ctx->lowLimit + MAX_DISTANCE > current) ? ctx->lowLimit : current - (MAX_DISTANCE - 1); + const BYTE* const dictBase = ctx->dictBase; + const BYTE* match; + int nbAttempts = ctx->searchNum; + int mnum = 0; + U16 *ptr0, *ptr1, delta0, delta1; + U32 matchIndex; + size_t matchLength = 0; + U32* HashPos; + + if (ip + MINMATCH > iHighLimit) return 1; + + /* HC4 match finder */ + HashPos = &HashTable[LZ4HC_hashPtr(ip)]; + matchIndex = *HashPos; + *HashPos = current; + + ptr0 = &DELTANEXTMAXD(current*2+1); + ptr1 = &DELTANEXTMAXD(current*2); + delta0 = delta1 = (U16)(current - matchIndex); + + while ((matchIndex < current) && (matchIndex>=lowLimit) && (nbAttempts)) { + nbAttempts--; + if (matchIndex >= dictLimit) { + match = base + matchIndex; + matchLength = LZ4_count(ip, match, iHighLimit); + } else { + const BYTE* vLimit = ip + (dictLimit - matchIndex); + match = dictBase + matchIndex; + if (vLimit > iHighLimit) vLimit = iHighLimit; + matchLength = LZ4_count(ip, match, vLimit); + if ((ip+matchLength == vLimit) && (vLimit < iHighLimit)) + matchLength += LZ4_count(ip+matchLength, base+dictLimit, iHighLimit); + } + + if (matchLength > best_mlen) { + best_mlen = matchLength; + if (matches) { + if (matchIndex >= dictLimit) + matches[mnum].off = (int)(ip - match); + else + matches[mnum].off = (int)(ip - (base + matchIndex)); /* virtual matchpos */ + matches[mnum].len = (int)matchLength; + mnum++; + } + if (best_mlen > LZ4_OPT_NUM) break; + } + + if (ip+matchLength >= iHighLimit) /* equal : no way to know if inf or sup */ + break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */ + + if (*(ip+matchLength) < *(match+matchLength)) { + *ptr0 = delta0; + ptr0 = &DELTANEXTMAXD(matchIndex*2); + if (*ptr0 == (U16)-1) break; + delta0 = *ptr0; + delta1 += delta0; + matchIndex -= delta0; + } else { + *ptr1 = delta1; + ptr1 = &DELTANEXTMAXD(matchIndex*2+1); + if (*ptr1 == (U16)-1) break; + delta1 = *ptr1; + delta0 += delta1; + matchIndex -= delta1; + } + } + + *ptr0 = (U16)-1; + *ptr1 = (U16)-1; + if (matchNum) *matchNum = mnum; + /* if (best_mlen > 8) return best_mlen-8; */ + if (!matchNum) return 1; + return 1; +} + + +FORCE_INLINE void LZ4HC_updateBinTree(LZ4HC_CCtx_internal* ctx, const BYTE* const ip, const BYTE* const iHighLimit) +{ + const BYTE* const base = ctx->base; + const U32 target = (U32)(ip - base); + U32 idx = ctx->nextToUpdate; + while(idx < target) + idx += LZ4HC_BinTree_InsertAndGetAllMatches(ctx, base+idx, iHighLimit, 8, NULL, NULL); +} + + +/** Tree updater, providing best match */ +FORCE_INLINE int LZ4HC_BinTree_GetAllMatches ( + LZ4HC_CCtx_internal* ctx, + const BYTE* const ip, const BYTE* const iHighLimit, + size_t best_mlen, LZ4HC_match_t* matches, const int fullUpdate) +{ + int mnum = 0; + if (ip < ctx->base + ctx->nextToUpdate) return 0; /* skipped area */ + if (fullUpdate) LZ4HC_updateBinTree(ctx, ip, iHighLimit); + best_mlen = LZ4HC_BinTree_InsertAndGetAllMatches(ctx, ip, iHighLimit, best_mlen, matches, &mnum); + ctx->nextToUpdate = (U32)(ip - ctx->base + best_mlen); + return mnum; +} + + +#define SET_PRICE(pos, ml, offset, ll, cost) \ +{ \ + while (last_pos < pos) { opt[last_pos+1].price = 1<<30; last_pos++; } \ + opt[pos].mlen = (int)ml; \ + opt[pos].off = (int)offset; \ + opt[pos].litlen = (int)ll; \ + opt[pos].price = (int)cost; \ +} + +FORCE_INLINE int LZ4HC_encodeSequence ( const BYTE** ip, BYTE** op, const BYTE** anchor, int matchLength, const BYTE* const match, limitedOutput_directive limit, BYTE* oend); + +static int LZ4HC_compress_optimal ( + LZ4HC_CCtx_internal* ctx, + const char* const source, + char* dest, + int inputSize, + int maxOutputSize, + limitedOutput_directive limit, + size_t sufficient_len, + const int fullUpdate + ) +{ + LZ4HC_optimal_t opt[LZ4_OPT_NUM + 1]; /* this uses a bit too much stack memory to my taste ... */ + LZ4HC_match_t matches[LZ4_OPT_NUM + 1]; + + const BYTE* ip = (const BYTE*) source; + const BYTE* anchor = ip; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = (iend - LASTLITERALS); + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + maxOutputSize; + + /* init */ + if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1; + ctx->end += inputSize; + ip++; + + /* Main Loop */ + while (ip < mflimit) { + size_t const llen = ip - anchor; + size_t last_pos = 0; + size_t match_num, cur, best_mlen, best_off; + memset(opt, 0, sizeof(LZ4HC_optimal_t)); + + match_num = LZ4HC_BinTree_GetAllMatches(ctx, ip, matchlimit, MINMATCH-1, matches, fullUpdate); + if (!match_num) { ip++; continue; } + + if ((size_t)matches[match_num-1].len > sufficient_len) { + /* good enough solution : immediate encoding */ + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + cur = 0; + last_pos = 1; + goto encode; + } + + /* set prices using matches at position = 0 */ + { size_t matchNb; + for (matchNb = 0; matchNb < match_num; matchNb++) { + size_t mlen = (matchNb>0) ? (size_t)matches[matchNb-1].len+1 : MINMATCH; + best_mlen = matches[matchNb].len; /* necessarily < sufficient_len < LZ4_OPT_NUM */ + for ( ; mlen <= best_mlen ; mlen++) { + size_t const cost = LZ4HC_sequencePrice(llen, mlen) - LZ4HC_literalsPrice(llen); + SET_PRICE(mlen, mlen, matches[matchNb].off, 0, cost); /* updates last_pos and opt[pos] */ + } } } + + if (last_pos < MINMATCH) { ip++; continue; } /* note : on clang at least, this test improves performance */ + + /* check further positions */ + opt[0].mlen = opt[1].mlen = 1; + for (cur = 1; cur <= last_pos; cur++) { + const BYTE* const curPtr = ip + cur; + + /* establish baseline price if cur is literal */ + { size_t price, litlen; + if (opt[cur-1].mlen == 1) { + /* no match at previous position */ + litlen = opt[cur-1].litlen + 1; + if (cur > litlen) { + price = opt[cur - litlen].price + LZ4HC_literalsPrice(litlen); + } else { + price = LZ4HC_literalsPrice(llen + litlen) - LZ4HC_literalsPrice(llen); + } + } else { + litlen = 1; + price = opt[cur - 1].price + LZ4HC_literalsPrice(1); + } + + if (price < (size_t)opt[cur].price) + SET_PRICE(cur, 1, 0, litlen, price); /* note : increases last_pos */ + } + + if (cur == last_pos || curPtr >= mflimit) break; + + match_num = LZ4HC_BinTree_GetAllMatches(ctx, curPtr, matchlimit, MINMATCH-1, matches, fullUpdate); + if ((match_num > 0) && (size_t)matches[match_num-1].len > sufficient_len) { + /* immediate encoding */ + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + last_pos = cur + 1; + goto encode; + } + + /* set prices using matches at position = cur */ + { size_t matchNb; + for (matchNb = 0; matchNb < match_num; matchNb++) { + size_t ml = (matchNb>0) ? (size_t)matches[matchNb-1].len+1 : MINMATCH; + best_mlen = (cur + matches[matchNb].len < LZ4_OPT_NUM) ? + (size_t)matches[matchNb].len : LZ4_OPT_NUM - cur; + + for ( ; ml <= best_mlen ; ml++) { + size_t ll, price; + if (opt[cur].mlen == 1) { + ll = opt[cur].litlen; + if (cur > ll) + price = opt[cur - ll].price + LZ4HC_sequencePrice(ll, ml); + else + price = LZ4HC_sequencePrice(llen + ll, ml) - LZ4HC_literalsPrice(llen); + } else { + ll = 0; + price = opt[cur].price + LZ4HC_sequencePrice(0, ml); + } + + if (cur + ml > last_pos || price < (size_t)opt[cur + ml].price) { + SET_PRICE(cur + ml, ml, matches[matchNb].off, ll, price); + } } } } + } /* for (cur = 1; cur <= last_pos; cur++) */ + + best_mlen = opt[last_pos].mlen; + best_off = opt[last_pos].off; + cur = last_pos - best_mlen; + +encode: /* cur, last_pos, best_mlen, best_off must be set */ + opt[0].mlen = 1; + while (1) { /* from end to beginning */ + size_t const ml = opt[cur].mlen; + int const offset = opt[cur].off; + opt[cur].mlen = (int)best_mlen; + opt[cur].off = (int)best_off; + best_mlen = ml; + best_off = offset; + if (ml > cur) break; + cur -= ml; + } + + /* encode all recorded sequences */ + cur = 0; + while (cur < last_pos) { + int const ml = opt[cur].mlen; + int const offset = opt[cur].off; + if (ml == 1) { ip++; cur++; continue; } + cur += ml; + if ( LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ip - offset, limit, oend) ) return 0; + } + } /* while (ip < mflimit) */ + + /* Encode Last Literals */ + { int lastRun = (int)(iend - anchor); + if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ + if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun > 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } + else *op++ = (BYTE)(lastRun<<ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend-anchor; + } + + /* End */ + return (int) ((char*)op-dest); +} +/* + LZ4 HC - High Compression Mode of LZ4 + Copyright (C) 2011-2017, Yann Collet. + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */ + + +/* ************************************* +* Tuning Parameter +***************************************/ + +/*! HEAPMODE : + * Select how default compression function will allocate workplace memory, + * in stack (0:fastest), or in heap (1:requires malloc()). + * Since workplace is rather large, heap mode is recommended. + */ +#ifndef LZ4HC_HEAPMODE +# define LZ4HC_HEAPMODE 1 +#endif + + +/*=== Dependency ===*/ + + + + + + +/************************************** +* HC Compression +**************************************/ +static void LZ4HC_init (LZ4HC_CCtx_internal* hc4, const BYTE* start) +{ + MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable)); + MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); + hc4->nextToUpdate = 64 KB; + hc4->base = start - 64 KB; + hc4->end = start; + hc4->dictBase = start - 64 KB; + hc4->dictLimit = 64 KB; + hc4->lowLimit = 64 KB; +} + + +/* Update chains up to ip (excluded) */ +FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) +{ + U16* const chainTable = hc4->chainTable; + U32* const hashTable = hc4->hashTable; + const BYTE* const base = hc4->base; + U32 const target = (U32)(ip - base); + U32 idx = hc4->nextToUpdate; + + while (idx < target) { + U32 const h = LZ4HC_hashPtr(base+idx); + size_t delta = idx - hashTable[h]; + if (delta>MAX_DISTANCE) delta = MAX_DISTANCE; + DELTANEXTU16(idx) = (U16)delta; + hashTable[h] = idx; + idx++; + } + + hc4->nextToUpdate = target; +} + + +FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* Index table will be updated */ + const BYTE* ip, const BYTE* const iLimit, + const BYTE** matchpos, + const int maxNbAttempts) +{ + U16* const chainTable = hc4->chainTable; + U32* const HashTable = hc4->hashTable; + const BYTE* const base = hc4->base; + const BYTE* const dictBase = hc4->dictBase; + const U32 dictLimit = hc4->dictLimit; + const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1); + U32 matchIndex; + int nbAttempts = maxNbAttempts; + size_t ml = 0; + + /* HC4 match finder */ + LZ4HC_Insert(hc4, ip); + matchIndex = HashTable[LZ4HC_hashPtr(ip)]; + + while ((matchIndex>=lowLimit) && (nbAttempts)) { + nbAttempts--; + if (matchIndex >= dictLimit) { + const BYTE* const match = base + matchIndex; + if (*(match+ml) == *(ip+ml) + && (LZ4_read32(match) == LZ4_read32(ip))) + { + size_t const mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH; + if (mlt > ml) { ml = mlt; *matchpos = match; } + } + } else { + const BYTE* const match = dictBase + matchIndex; + if (LZ4_read32(match) == LZ4_read32(ip)) { + size_t mlt; + const BYTE* vLimit = ip + (dictLimit - matchIndex); + if (vLimit > iLimit) vLimit = iLimit; + mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH; + if ((ip+mlt == vLimit) && (vLimit < iLimit)) + mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit); + if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */ + } + } + matchIndex -= DELTANEXTU16(matchIndex); + } + + return (int)ml; +} + + +FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch ( + LZ4HC_CCtx_internal* hc4, + const BYTE* const ip, + const BYTE* const iLowLimit, + const BYTE* const iHighLimit, + int longest, + const BYTE** matchpos, + const BYTE** startpos, + const int maxNbAttempts) +{ + U16* const chainTable = hc4->chainTable; + U32* const HashTable = hc4->hashTable; + const BYTE* const base = hc4->base; + const U32 dictLimit = hc4->dictLimit; + const BYTE* const lowPrefixPtr = base + dictLimit; + const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1); + const BYTE* const dictBase = hc4->dictBase; + U32 matchIndex; + int nbAttempts = maxNbAttempts; + int delta = (int)(ip-iLowLimit); + + + /* First Match */ + LZ4HC_Insert(hc4, ip); + matchIndex = HashTable[LZ4HC_hashPtr(ip)]; + + while ((matchIndex>=lowLimit) && (nbAttempts)) { + nbAttempts--; + if (matchIndex >= dictLimit) { + const BYTE* matchPtr = base + matchIndex; + if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) { + if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { + int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); + int back = 0; + + while ((ip+back > iLowLimit) + && (matchPtr+back > lowPrefixPtr) + && (ip[back-1] == matchPtr[back-1])) + back--; + + mlt -= back; + + if (mlt > longest) { + longest = (int)mlt; + *matchpos = matchPtr+back; + *startpos = ip+back; + } } } + } else { + const BYTE* const matchPtr = dictBase + matchIndex; + if (LZ4_read32(matchPtr) == LZ4_read32(ip)) { + size_t mlt; + int back=0; + const BYTE* vLimit = ip + (dictLimit - matchIndex); + if (vLimit > iHighLimit) vLimit = iHighLimit; + mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; + if ((ip+mlt == vLimit) && (vLimit < iHighLimit)) + mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit); + while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--; + mlt -= back; + if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; } + } + } + matchIndex -= DELTANEXTU16(matchIndex); + } + + return longest; +} + + + +#define LZ4HC_DEBUG 0 +#if LZ4HC_DEBUG +static unsigned debug = 0; +#endif + + +/* LZ4HC_encodeSequence() : + * @return : 0 if ok, + * 1 if buffer issue detected */ +FORCE_INLINE int LZ4HC_encodeSequence ( const BYTE** ip, BYTE** op, const BYTE** anchor, int matchLength, const BYTE* const match, limitedOutput_directive limit, BYTE* oend) +{ + size_t length; + BYTE* token; + +#if LZ4HC_DEBUG + if (debug) printf("literal : %u -- match : %u -- offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match)); +#endif + + /* Encode Literal length */ + length = (size_t)(*ip - *anchor); + token = (*op)++; + if ((limit) && ((*op + (length >> 8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */ + if (length >= RUN_MASK) { + size_t len = length - RUN_MASK; + *token = (RUN_MASK << ML_BITS); + for(; len >= 255 ; len -= 255) *(*op)++ = 255; + *(*op)++ = (BYTE)len; + } else { + *token = (BYTE)(length << ML_BITS); + } + + /* Copy Literals */ + LZ4_wildCopy(*op, *anchor, (*op) + length); + *op += length; + + /* Encode Offset */ + LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2; + + /* Encode MatchLength */ + length = (size_t)(matchLength - MINMATCH); + if ((limit) && (*op + (length >> 8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */ + if (length >= ML_MASK) { + *token += ML_MASK; + length -= ML_MASK; + for(; length >= 510 ; length -= 510) { *(*op)++ = 255; *(*op)++ = 255; } + if (length >= 255) { length -= 255; *(*op)++ = 255; } + *(*op)++ = (BYTE)length; + } else { + *token += (BYTE)(length); + } + + /* Prepare next loop */ + *ip += matchLength; + *anchor = *ip; + + return 0; +} + +/* btopt */ + + +static int LZ4HC_compress_hashChain ( + LZ4HC_CCtx_internal* const ctx, + const char* const source, + char* const dest, + int* srcSizePtr, + int const maxOutputSize, + unsigned maxNbAttempts, + limitedOutput_directive limit + ) +{ + const int inputSize = *srcSizePtr; + + const BYTE* ip = (const BYTE*) source; + const BYTE* anchor = ip; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = (iend - LASTLITERALS); + + BYTE* optr = (BYTE*) dest; + BYTE* op = (BYTE*) dest; + BYTE* oend = op + maxOutputSize; + + int ml, ml2, ml3, ml0; + const BYTE* ref = NULL; + const BYTE* start2 = NULL; + const BYTE* ref2 = NULL; + const BYTE* start3 = NULL; + const BYTE* ref3 = NULL; + const BYTE* start0; + const BYTE* ref0; + + /* init */ + *srcSizePtr = 0; + if (limit == limitedDestSize && maxOutputSize < 1) return 0; /* Impossible to store anything */ + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + + ctx->end += inputSize; + if (limit == limitedDestSize) oend -= LASTLITERALS; /* Hack for support limitations LZ4 decompressor */ + if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ + + ip++; + + /* Main Loop */ + while (ip < mflimit) { + ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts); + if (!ml) { ip++; continue; } + + /* saved, in case we would skip too much */ + start0 = ip; + ref0 = ref; + ml0 = ml; + +_Search2: + if (ip+ml < mflimit) + ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2, maxNbAttempts); + else + ml2 = ml; + + if (ml2 == ml) { /* No better match */ + optr = op; + if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow; + continue; + } + + if (start0 < ip) { + if (start2 < ip + ml0) { /* empirical */ + ip = start0; + ref = ref0; + ml = ml0; + } + } + + /* Here, start0==ip */ + if ((start2 - ip) < 3) { /* First Match too small : removed */ + ml = ml2; + ip = start2; + ref =ref2; + goto _Search2; + } + +_Search3: + /* At this stage, we have : + * ml2 > ml1, and + * ip1+3 <= ip2 (usually < ip1+ml1) */ + if ((start2 - ip) < OPTIMAL_ML) { + int correction; + int new_ml = ml; + if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; + if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH; + correction = new_ml - (int)(start2 - ip); + if (correction > 0) { + start2 += correction; + ref2 += correction; + ml2 -= correction; + } + } + /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */ + + if (start2 + ml2 < mflimit) + ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts); + else + ml3 = ml2; + + if (ml3 == ml2) { /* No better match : 2 sequences to encode */ + /* ip & ref are known; Now for ml */ + if (start2 < ip+ml) ml = (int)(start2 - ip); + /* Now, encode 2 sequences */ + optr = op; + if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow; + ip = start2; + optr = op; + if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) goto _dest_overflow; + continue; + } + + if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */ + if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */ + if (start2 < ip+ml) { + int correction = (int)(ip+ml - start2); + start2 += correction; + ref2 += correction; + ml2 -= correction; + if (ml2 < MINMATCH) { + start2 = start3; + ref2 = ref3; + ml2 = ml3; + } + } + + optr = op; + if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow; + ip = start3; + ref = ref3; + ml = ml3; + + start0 = start2; + ref0 = ref2; + ml0 = ml2; + goto _Search2; + } + + start2 = start3; + ref2 = ref3; + ml2 = ml3; + goto _Search3; + } + + /* + * OK, now we have 3 ascending matches; let's write at least the first one + * ip & ref are known; Now for ml + */ + if (start2 < ip+ml) { + if ((start2 - ip) < (int)ML_MASK) { + int correction; + if (ml > OPTIMAL_ML) ml = OPTIMAL_ML; + if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH; + correction = ml - (int)(start2 - ip); + if (correction > 0) { + start2 += correction; + ref2 += correction; + ml2 -= correction; + } + } else { + ml = (int)(start2 - ip); + } + } + optr = op; + if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) goto _dest_overflow; + + ip = start2; + ref = ref2; + ml = ml2; + + start2 = start3; + ref2 = ref3; + ml2 = ml3; + + goto _Search3; + } + +_last_literals: + /* Encode Last Literals */ + { size_t lastRunSize = (size_t)(iend - anchor); /* literals */ + size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255; + size_t const totalSize = 1 + litLength + lastRunSize; + if (limit == limitedDestSize) oend += LASTLITERALS; /* restore correct value */ + if (limit && (op + totalSize > oend)) { + if (limit == limitedOutput) return 0; /* Check output limit */ + /* adapt lastRunSize to fill 'dest' */ + lastRunSize = (size_t)(oend - op) - 1; + litLength = (lastRunSize + 255 - RUN_MASK) / 255; + lastRunSize -= litLength; + } + ip = anchor + lastRunSize; + + if (lastRunSize >= RUN_MASK) { + size_t accumulator = lastRunSize - RUN_MASK; + *op++ = (RUN_MASK << ML_BITS); + for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255; + *op++ = (BYTE) accumulator; + } else { + *op++ = (BYTE)(lastRunSize << ML_BITS); + } + memcpy(op, anchor, lastRunSize); + op += lastRunSize; + } + + /* End */ + *srcSizePtr = (int) (((const char*)ip) - source); + return (int) (((char*)op)-dest); + +_dest_overflow: + if (limit == limitedDestSize) { + op = optr; /* restore correct out pointer */ + goto _last_literals; + } + return 0; +} + +static int LZ4HC_getSearchNum(int compressionLevel) +{ + switch (compressionLevel) { + default: return 0; /* unused */ + case 11: return 128; + case 12: return 1<<10; + } +} + +static int LZ4HC_compress_generic ( + LZ4HC_CCtx_internal* const ctx, + const char* const src, + char* const dst, + int* const srcSizePtr, + int const dstCapacity, + int cLevel, + limitedOutput_directive limit + ) +{ + if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe to reconsider */ + if (cLevel > 9) { + if (limit == limitedDestSize) cLevel = 10; + switch (cLevel) { + case 10: + return LZ4HC_compress_hashChain(ctx, src, dst, srcSizePtr, dstCapacity, 1 << (15-1), limit); + case 11: + ctx->searchNum = LZ4HC_getSearchNum(cLevel); + return LZ4HC_compress_optimal(ctx, src, dst, *srcSizePtr, dstCapacity, limit, 128, 0); + default: + case 12: + ctx->searchNum = LZ4HC_getSearchNum(cLevel); + return LZ4HC_compress_optimal(ctx, src, dst, *srcSizePtr, dstCapacity, limit, LZ4_OPT_NUM, 1); + } + } + return LZ4HC_compress_hashChain(ctx, src, dst, srcSizePtr, dstCapacity, 1 << (cLevel-1), limit); /* levels 1-9 */ +} + + +int LZ4_sizeofStateHC(void) { return sizeof(LZ4_streamHC_t); } + +int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) +{ + LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; + if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */ + LZ4HC_init (ctx, (const BYTE*)src); + if (dstCapacity < LZ4_compressBound(srcSize)) + return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput); + else + return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, noLimit); +} + +int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) +{ +#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 + LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); +#else + LZ4_streamHC_t state; + LZ4_streamHC_t* const statePtr = &state; +#endif + int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel); +#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 + free(statePtr); +#endif + return cSize; +} + +/* LZ4_compress_HC_destSize() : + * currently, only compatible with Hash Chain implementation, + * hence limit compression level to LZ4HC_CLEVEL_OPT_MIN-1*/ +int LZ4_compress_HC_destSize(void* LZ4HC_Data, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel) +{ + LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse; + LZ4HC_init(ctx, (const BYTE*) source); + return LZ4HC_compress_generic(ctx, source, dest, sourceSizePtr, targetDestSize, cLevel, limitedDestSize); +} + + + +/************************************** +* Streaming Functions +**************************************/ +/* allocation */ +LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); } +int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_streamHCPtr); return 0; } + + +/* initialization */ +void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) +{ + LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= sizeof(size_t) * LZ4_STREAMHCSIZE_SIZET); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */ + LZ4_streamHCPtr->internal_donotuse.base = NULL; + if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX; /* cap compression level */ + LZ4_streamHCPtr->internal_donotuse.compressionLevel = compressionLevel; + LZ4_streamHCPtr->internal_donotuse.searchNum = LZ4HC_getSearchNum(compressionLevel); +} + +int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize) +{ + LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; + if (dictSize > 64 KB) { + dictionary += dictSize - 64 KB; + dictSize = 64 KB; + } + LZ4HC_init (ctxPtr, (const BYTE*)dictionary); + ctxPtr->end = (const BYTE*)dictionary + dictSize; + if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) + LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS); + else + if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); + return dictSize; +} + + +/* compression */ + +static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) +{ + if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) + LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS); + else + if (ctxPtr->end >= ctxPtr->base + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ + + /* Only one memory segment for extDict, so any previous extDict is lost at this stage */ + ctxPtr->lowLimit = ctxPtr->dictLimit; + ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base); + ctxPtr->dictBase = ctxPtr->base; + ctxPtr->base = newBlock - ctxPtr->dictLimit; + ctxPtr->end = newBlock; + ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */ +} + +static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, + const char* src, char* dst, + int* srcSizePtr, int dstCapacity, + limitedOutput_directive limit) +{ + LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; + /* auto-init if forgotten */ + if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const BYTE*) src); + + /* Check overflow */ + if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) { + size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit; + if (dictSize > 64 KB) dictSize = 64 KB; + LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize); + } + + /* Check if blocks follow each other */ + if ((const BYTE*)src != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src); + + /* Check overlapping input/dictionary space */ + { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr; + const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; + const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; + if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) { + if (sourceEnd > dictEnd) sourceEnd = dictEnd; + ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase); + if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit; + } + } + + return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit); +} + +int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity) +{ + if (dstCapacity < LZ4_compressBound(srcSize)) + return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput); + else + return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, noLimit); +} + +int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize) +{ + LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; + if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN) LZ4HC_init(ctxPtr, (const BYTE*)src); /* not compatible with btopt implementation */ + return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, limitedDestSize); +} + + + +/* dictionary saving */ + +int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize) +{ + LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; + int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit)); + if (dictSize > 64 KB) dictSize = 64 KB; + if (dictSize < 4) dictSize = 0; + if (dictSize > prefixSize) dictSize = prefixSize; + memmove(safeBuffer, streamPtr->end - dictSize, dictSize); + { U32 const endIndex = (U32)(streamPtr->end - streamPtr->base); + streamPtr->end = (const BYTE*)safeBuffer + dictSize; + streamPtr->base = streamPtr->end - endIndex; + streamPtr->dictLimit = endIndex - dictSize; + streamPtr->lowLimit = endIndex - dictSize; + if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit; + } + return dictSize; +} + + +/*********************************** +* Deprecated Functions +***********************************/ +/* These functions currently generate deprecation warnings */ +/* Deprecated compression functions */ +int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); } +int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); } +int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } +int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); } +int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); } +int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); } +int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } +int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); } +int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); } +int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); } + + +/* Deprecated streaming functions */ +int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; } + +int LZ4_resetStreamStateHC(void* state, char* inputBuffer) +{ + LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; + if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */ + LZ4HC_init(ctx, (const BYTE*)inputBuffer); + ctx->inputBuffer = (BYTE*)inputBuffer; + return 0; +} + +void* LZ4_createHC (char* inputBuffer) +{ + LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t)); + if (hc4 == NULL) return NULL; /* not enough memory */ + LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer); + hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer; + return hc4; +} + +int LZ4_freeHC (void* LZ4HC_Data) { FREEMEM(LZ4HC_Data); return 0; } + +int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel) +{ + return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, noLimit); +} + +int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel) +{ + return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput); +} + +char* LZ4_slideInputBufferHC(void* LZ4HC_Data) +{ + LZ4HC_CCtx_internal* const hc4 = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse; + int const dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB); + return (char*)(hc4->inputBuffer + dictSize); +} diff --git a/tools/rasm_src/minilib.h b/tools/rasm_src/minilib.h new file mode 100644 index 0000000..99d55eb --- /dev/null +++ b/tools/rasm_src/minilib.h @@ -0,0 +1,1151 @@ +#define __FILENAME__ "minilib.h" + +#include<string.h> +#include<stdlib.h> +#include<stddef.h> +#include<stdint.h> +#include<stdarg.h> +#include<stdio.h> +#include<errno.h> +#include<ctype.h> +#include<time.h> +#include<math.h> +#include<sys/types.h> +#include<sys/stat.h> +#include<fcntl.h> +#include<errno.h> +#ifdef OS_WIN +#include<io.h> +#include<limits.h> +#include<direct.h> +#define snprintf _snprintf +#endif +#include<ctype.h> +#include<stdio.h> +#include<stdlib.h> +#ifndef OS_WIN +#include<unistd.h> +#endif +#include<string.h> +#include<setjmp.h> +#include<errno.h> +#include<sys/timeb.h> + +#ifndef ARG_MAX +#define ARG_MAX 8191 +#endif + + + +#define MemFree free +#define MemRealloc realloc +#define MemMalloc malloc +#define MemMove memmove +#ifdef OS_WIN +#define TxtStrDup _strdup +#else +#define TxtStrDup strdup +#endif + +#define loginfo(...); {printf(__VA_ARGS__);printf("\n");} +#define logdebug(...); {printf(__VA_ARGS__);printf("\n");} +#define logwarn(...); {printf(__VA_ARGS__);printf("\n");} +#define logerr(...); {printf(__VA_ARGS__);printf("\n");} + +#define INTERNAL_ERROR 1 +#define ABORT_ERROR 7 + +#define MAX_LINE_BUFFER 16384 + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +static int _static_library_nbfile_opened=0; +static int _static_library_nbfile_opened_max=0; + +void _internal_ObjectArrayAddDynamicValue(void **zearray, void *zeobject, int object_size,int curline, char *curfunc, char *cursource); +void _internal_ObjectArrayAddDynamicValueConcat(void **zearray, int *nbfields, int *maxfields, void *zeobject, int object_size, int curline, char *curfunc, char *cursource); +#define ObjectArrayAddDynamicValue(zearray,zeobject,objsize) _internal_ObjectArrayAddDynamicValue(zearray,zeobject,objsize,__LINE__,FUNC,__FILENAME__) +#define ObjectArrayAddDynamicValueConcat(zearray,nbv,maxv,zeobject,objsize) _internal_ObjectArrayAddDynamicValueConcat(zearray,nbv,maxv,zeobject,objsize,__LINE__,FUNC,__FILENAME__) +void _internal_IntArrayAddDynamicValueConcat(int **zearray, int *nbval, int *maxval, int zevalue, int curline, char *curfunc, char *cursource); +#define IntArrayAddDynamicValueConcat(zearray,nbv,maxv,zevalue) _internal_IntArrayAddDynamicValueConcat(zearray,nbv,maxv,zevalue,__LINE__,FUNC,__FILENAME__) +void _internal_FieldArrayAddDynamicValue(char ***zearray, char *zevalue, int curline, char *curfunc, char *cursource); +#define FieldArrayAddDynamicValue(zearray,zevalue) _internal_FieldArrayAddDynamicValue(zearray,zevalue,__LINE__,FUNC,__FILENAME__) +void _internal_FieldArrayAddDynamicValueConcat(char ***zearray, int *nbfields, int *maxfields, char *zevalue, int curline, char *curfunc, char *cursource); +#define FieldArrayAddDynamicValueConcat(zearray,nb,maxf,zevalue) _internal_FieldArrayAddDynamicValueConcat(zearray,nb,maxf,zevalue,__LINE__,FUNC,__FILENAME__) + + +long long FileGetSize(char *filename); + +int MinMaxInt(int zeval, int zemin, int zemax) +{ + #undef FUNC + #define FUNC "MinMaxInt" + + if (zeval<zemin) return zemin; + if (zeval>zemax) return zemax; + return zeval; +} + +/* (c) FSF */ +#ifdef __WATCOMC__ +size_t strnlen (s, maxlen) + register const char *s; + size_t maxlen; +{ + register const char *e; + size_t n; + + for (e = s, n = 0; *e && n < maxlen; e++, n++) + ; + return n; +} +#endif + + +char *TxtStrDupLen(char *str, int *len) +{ + #undef FUNC + #define FUNC "TxtStrDupLen" + + char *newstr; + *len=strlen(str)+1; + newstr=MemMalloc(*len); + strcpy(newstr,str); + return newstr; +} + +void _internal_ObjectArrayAddDynamicValueConcat(void **zearray, int *nbfields, int *maxfields, void *zeobject, int object_size, int curline, char *curfunc, char *cursource) +{ + #undef FUNC + #define FUNC "ObjectArrayAddDynamicValueConcat" + + char *dst; + + if ((*zearray)==NULL) { + *nbfields=1; + *maxfields=3; + (*zearray)=malloc((*maxfields)*object_size); + } else { + *nbfields=(*nbfields)+1; + if (*nbfields>=*maxfields) { + *maxfields=(*maxfields)*2; + (*zearray)=realloc((*zearray),(*maxfields)*object_size); + } + } + /* using direct calls because it is more interresting to know which is the caller */ + dst=((char *)(*zearray))+((*nbfields)-1)*object_size; + /* control of memory for overflow */ + memcpy(dst,zeobject,object_size); +} + +/*** + Add a value to a list of integers + Reallocate memory on the fly + + zearray: pointer to the array of integers + nbval: pointer to the current index + maxval: pointer to the current allocated memory + zevalue: integer value to concat to + + output: the pointer to the array is modified because the + function reallocate memory to store the new string at + the end of the array. +*/ +void _internal_IntArrayAddDynamicValueConcat(int **zearray, int *nbval, int *maxval, int zevalue, int curline, char *curfunc, char *cursource) +{ + #undef FUNC + #define FUNC "IntArrayAddDynamicValue" + + if ((*zearray)==NULL) { + *nbval=1; + *maxval=4; + (*zearray)=MemMalloc(sizeof(int)*(*maxval)); + } else { + *nbval=*nbval+1; + if (*nbval>*maxval) { + *maxval=(*maxval)*2; + (*zearray)=realloc((*zearray),sizeof(int)*(*maxval)); + } + } + (*zearray)[(*nbval)-1]=zevalue; +} + +/*** + CSVGetFieldArrayNumber + + count array elements +*/ +int CSVGetFieldArrayNumber(char **myfield) +{ + #undef FUNC + #define FUNC "CSVGetFieldArrayNumber" + + int n=0; + + if (myfield==NULL) + return 0; + + while (myfield[n]!=NULL) n++; + + return n; + +} +/*** + * TxtSplit + * + * split the parameter string into an array of strings + */ +char **TxtSplitWithChar(char *in_str, char split_char) +{ + #undef FUNC + #define FUNC "TxtSplitWithChar" + + char **tab=NULL; + char *match_str; + int redo=1; + int idx,idmax; + + match_str=in_str; + + while (redo && *in_str) { + while (*match_str && *match_str!=split_char) match_str++; + redo=*match_str; + *match_str=0; + FieldArrayAddDynamicValueConcat(&tab,&idx,&idmax,in_str); + in_str=++match_str; + } + + return tab; +} + +/*** + Add a value to a list of strings + Reallocate memory on the fly + + input: pointer to an array of string + string value + + output: the pointer to the array is modified because the + function reallocate memory to store the new string at + the end of the array. +*/ +void _internal_FieldArrayAddDynamicValue(char ***zearray, char *zevalue, int curline, char *curfunc, char *cursource) +{ + #undef FUNC + #define FUNC "FieldArrayAddDynamicValue" + int nbfield; + if ((*zearray)==NULL) nbfield=2; else nbfield=CSVGetFieldArrayNumber((*zearray))+2; + /* using direct calls because it is more interresting to know which is the caller */ + (*zearray)=realloc((*zearray),nbfield*sizeof(char *)); + (*zearray)[nbfield-2]=TxtStrDup(zevalue); + (*zearray)[nbfield-1]=NULL; +} +void _internal_FieldArrayAddDynamicValueConcat(char ***zearray, int *nbfields, int *maxfields, char *zevalue, int curline, char *curfunc, char *cursource) +{ + #undef FUNC + #define FUNC "FieldArrayAddDynamicValueConcat" + + if ((*zearray)==NULL) { + *nbfields=1; + *maxfields=10; + (*zearray)=realloc(NULL,(*maxfields)*sizeof(char *)); + } else { + *nbfields=(*nbfields)+1; + if (*nbfields>=*maxfields) { + *maxfields=(*maxfields)*2; + (*zearray)=MemRealloc((*zearray),(*maxfields)*sizeof(char *)); + } + } + /* using direct calls because it is more interresting to know which is the caller */ + (*zearray)[(*nbfields)-1]=TxtStrDup(zevalue); + (*zearray)[(*nbfields)]=NULL; +} + + + +/*** + CSVFreeFields + + free allocated memory for fields +*/ +void CSVFreeFields(char **fields) +{ + #undef FUNC + #define FUNC "CSVFreeFields" + + int i=0; + if (fields!=NULL) + { + /*loginfo("%8X",fields); + if (fields[i]==NULL) + loginfo("NULL i=%d",i); */ + + while (fields[i]!=NULL) + { + MemFree(fields[i]); + i++; + } + MemFree(fields); + } +} +void FreeArrayDynamicValue(char ***zearray) +{ + CSVFreeFields(*zearray); + *zearray=NULL; +} + + +void CSVFreeFields(char **fields); +#define FreeFields(fields) CSVFreeFields(fields) + + +/************************** File operation ******************************/ + + +/*** + s_fileid + structure used by FileReadLine and FileWriteLine to manage multiple files at a time +*/ +struct s_fileid +{ + FILE *file_id; + char *filename; + char opening_type[4]; + int cpt; + struct s_fileid *next; + /* v2 */ + int closed; + unsigned long curpos; +}; + +static struct s_fileid *fileidROOT=NULL; + +/*** + FileGetStructFromName + + input: filename + output: file structure + NULL if not found +*/ +struct s_fileid *FileGetStructFromName(char *filename) +{ + #undef FUNC + #define FUNC "FileGetStructFromName" + struct s_fileid *curfile; + struct s_fileid *prevfile; + + if (!filename) + { + logerr("filename must not be NULL"); + exit(ABORT_ERROR); + } + + if (strnlen(filename,PATH_MAX)==PATH_MAX) + { + logerr("cannot open this file because the argument size is bigger than PATH_MAX (%d)",PATH_MAX); + exit(ABORT_ERROR); + } + + /* try to find the file in the list */ + curfile=fileidROOT; + prevfile=NULL; + while (curfile!=NULL) + { + if (!strcmp(curfile->filename,filename)) { + break; + } else { + prevfile=curfile; + curfile=curfile->next; + } + } + /* put the struct to the top of the list */ + if (curfile && prevfile) { + prevfile->next=curfile->next; + curfile->next=fileidROOT; + fileidROOT=curfile; + } + + return curfile; +} + +/*** + FileOpen function + + open a file in any mode (r,w,a,r+,w+,a+) + check if the file is already open + check for conflicts +*/ +FILE *FileOpen(char *filename, char *opening_type) +{ + #undef FUNC + #define FUNC "FileOpen" + struct s_fileid *curfile; + struct s_fileid *oldfile; + + /* check parameters coherency */ + if (strlen(opening_type)>3) + { + logerr("illegal opening type (too long)"); + exit(ABORT_ERROR); + } + if (strcmp(opening_type,"a") && strcmp(opening_type,"w") && strcmp(opening_type,"r") + && strcmp(opening_type,"a+") && strcmp(opening_type,"w+") && strcmp(opening_type,"r+") && strcmp(opening_type,"rb")) + { + logerr("illegal opening type [%s]\nallowed options are: r,w,a,r+,w+,a+",opening_type); + exit(ABORT_ERROR); + } + + curfile=FileGetStructFromName(filename); + + /* if curfile is NULL then the file is not opened yet */ + if (!curfile) + { + /* insert a new record */ + _static_library_nbfile_opened++; + if (_static_library_nbfile_opened>_static_library_nbfile_opened_max) + _static_library_nbfile_opened_max=_static_library_nbfile_opened; + curfile=MemMalloc(sizeof(struct s_fileid)); + memset(curfile,0,sizeof(struct s_fileid)); + curfile->filename=MemMalloc(strlen(filename)+1); + strcpy(curfile->filename,filename); + strcpy(curfile->opening_type,opening_type); + curfile->next=fileidROOT; + curfile->cpt=0; + fileidROOT=curfile; + } + else + { + if (strcmp(curfile->opening_type,opening_type)) + { + logerr("You can't open the file [%s] in [%s] mode cause it's already open in [%s] mode",filename,opening_type,curfile->opening_type); + exit(ABORT_ERROR); + } + if (!curfile->closed) { + /* already opened, just return the id */ + return curfile->file_id; + } + } + + curfile->file_id=fopen(filename,opening_type); + if (!curfile->file_id) + { + if (errno==EMFILE) { + /* too many files opened, close the latest of the list */ + oldfile=fileidROOT; + while (oldfile->next && !oldfile->next->closed) oldfile=oldfile->next; + if (oldfile==curfile) { + logerr("cannot open a single file!"); + exit(INTERNAL_ERROR); + } + /* save position and close the file */ + oldfile->curpos=ftell(oldfile->file_id); + fclose(oldfile->file_id); + oldfile->file_id=0; + oldfile->closed=1; + /* then try again */ + curfile->file_id=fopen(filename,opening_type); + if (curfile->file_id) { + if (curfile->curpos) { + fseek(curfile->file_id,curfile->curpos,SEEK_SET); + curfile->curpos=0; + } + + logdebug("opening file [%s] in %s mode (too many opened files limit reached)",filename,opening_type); + return curfile->file_id; + } + } + + logerr("failed to open file [%s] with mode [%s]",filename,opening_type); + logerr("check empty space and permissions"); + exit(ABORT_ERROR); + } + + /* go on previous position */ + if (curfile->curpos) { + fseek(curfile->file_id,curfile->curpos,SEEK_SET); + curfile->curpos=0; + } + + //logdebug("opening file [%s] in %s mode",filename,opening_type); + return curfile->file_id; +} + +struct s_fileid *FileGetStructFromID(FILE *file_id); + +void FileSeekBinary(char *filename,int pos, int st) +{ + #undef FUNC + #define FUNC "FileSeekBinary" + FILE *last_id=NULL; + struct s_fileid *curfile=NULL; + int err; + + last_id=FileOpen(filename,"r"); + if ((err=fseek(last_id,pos,st))!=0) { + logerr("error seeking %s (%d)",filename,ferror(last_id)); + exit(ABORT_ERROR); + } + + curfile=FileGetStructFromID(last_id); + switch (st) { + case SEEK_SET: curfile->curpos=pos; break; + case SEEK_CUR: curfile->curpos+=pos; break; + case SEEK_END: logerr("TODO§§§"); break; + default:logerr("unknown SEEK mode!");exit(INTERNAL_ERROR); + } +} + +/*** + FileGetStructFromID + + retrieve the file structure from the tree, with his ID +*/ +struct s_fileid *FileGetStructFromID(FILE *file_id) +{ + #undef FUNC + #define FUNC "FileGetStructFromID" + struct s_fileid *curfile; + struct s_fileid *prevfile; + + curfile=fileidROOT; + prevfile=NULL; + while (curfile!=NULL) + { + if (curfile->file_id==file_id) { + break; + } else { + prevfile=curfile; + curfile=curfile->next; + } + } + if (!curfile) + { + logerr("ID requested for an unknown file! (was supposed to be opened)"); + exit(INTERNAL_ERROR); + } + /* put the struct to the top of the list */ + if (prevfile) { + prevfile->next=curfile->next; + curfile->next=fileidROOT; + fileidROOT=curfile; + } + + return curfile; +} + +/*** + FileClose function + + check for closing return code + free the memory file structure +*/ +void FileClose(FILE *file_id) +{ + #undef FUNC + #define FUNC "FileClose" + struct s_fileid *curfile; + struct s_fileid *unlinkcell; + + curfile=FileGetStructFromID(file_id); + + if (!curfile->closed) { + if (fclose(curfile->file_id)) + { + logerr("error while closing file [%s]",curfile->filename); + } + } else { + /* already closed */ + } + + /* unlink the cell from ROOT */ + if (curfile==fileidROOT) + { + fileidROOT=curfile->next; + } + else + { + unlinkcell=fileidROOT; + while (unlinkcell->next!=curfile) + unlinkcell=unlinkcell->next; + unlinkcell->next=curfile->next; + } + MemFree(curfile->filename); + MemFree(curfile); + _static_library_nbfile_opened--; +} + +/*** + FileAddCPT + + add n to counter when reading or writing in a file +*/ +void FileAddCPT(FILE *file_id, int n) +{ + #undef FUNC + #define FUNC "FileAddCPT" + struct s_fileid *curfile; + + curfile=FileGetStructFromID(file_id); + curfile->cpt+=n; +} +#define FileIncCPT(file_id) FileAddCPT(file_id,1) + +/*** + FileGetCPT + + Get file counter information + input: file_id +*/ +int FileGetCPT(FILE *file_id) +{ + #undef FUNC + #define FUNC "FileGetCPT" + struct s_fileid *curfile; + + curfile=FileGetStructFromID(file_id); + return curfile->cpt; +} +/*** + FileGetCPTFromName + + Get file counter information + input: filename +*/ +int FileGetCPTFromName(char *filename) +{ + #undef FUNC + #define FUNC "FileGetCPTFromName" + struct s_fileid *curfile; + + curfile=FileGetStructFromName(filename); + if (!curfile) + { + logerr("You requested a counter for a file that is not opened! [%s]",filename); + exit(INTERNAL_ERROR); + } + return curfile->cpt; +} + + + +char *_internal_fgetsClose(char *buffer, int maxlen, FILE *f) +{ + #undef FUNC + #define FUNC "_internal_fgetsClose" + return NULL; +} + +/*** + FileReadLine/FileReadLineXML function + + input: + - filename + + output: + - a static buffer with the line read + + this function can handle many file simultaneously + just use different filenames without regarding to opened/closed pointer + the opened handles are automatically closed when the end of the file is reached + you are only limited by the system, not by the code + + the XML version ass carriage returns after closing tag + this can be usefull for parsing when reading XML file in a single line +*/ +enum e_reading_mode { +RAW_READING, +CLOSE_READING +}; + +char *_internal_fgetsmulti(char *filename, int read_mode) +{ + #undef FUNC + #define FUNC "_internal_fgetsmulti" + static char buffer[MAX_LINE_BUFFER+1]={0}; + FILE *last_id=NULL; + char * (*_file_get_string)(char *, int, FILE *); + + last_id=FileOpen(filename,"r"); + + switch (read_mode) + { + case RAW_READING:_file_get_string=fgets;break; + case CLOSE_READING:_file_get_string=_internal_fgetsClose;break; + default:logerr("Unknown read mode! (%d)",read_mode); + } + + if (_file_get_string(buffer,MAX_LINE_BUFFER,last_id)!=NULL) + { + FileIncCPT(last_id); + if (strnlen(buffer,MAX_LINE_BUFFER)==MAX_LINE_BUFFER) + { + logerr("line %d is too long! More than %d characters\n",FileGetCPT(last_id),MAX_LINE_BUFFER); + exit(INTERNAL_ERROR); + } + return buffer; + } + else + { + /* End of file, we close the handle */ + logdebug("%d line(s) read from %s",FileGetCPT(last_id),filename); + FileClose(last_id); + return NULL; + } +} + +char **_internal_fgetsmultilines(char *filename, int read_mode) +{ + #undef FUNC + #define FUNC "_internal_fgetsmultilines" + static char buffer[MAX_LINE_BUFFER+1]={0}; + FILE *last_id=NULL; + char * (*_file_get_string)(char *, int, FILE *); + char **lines_buffer=NULL; + int cur_line=0,max_line=0; + + last_id=FileOpen(filename,"r"); + + switch (read_mode) + { + case RAW_READING:_file_get_string=fgets;break; + case CLOSE_READING:_file_get_string=_internal_fgetsClose;break; + default:logerr("Unknown read mode! (%d)",read_mode); + } + + + while (_file_get_string(buffer,MAX_LINE_BUFFER,last_id)!=NULL) + { + FileIncCPT(last_id); + if (strnlen(buffer,MAX_LINE_BUFFER)==MAX_LINE_BUFFER) + { + logerr("line %d is too long! More than %d characters\n",FileGetCPT(last_id),MAX_LINE_BUFFER); + exit(INTERNAL_ERROR); + } + FieldArrayAddDynamicValueConcat(&lines_buffer,&cur_line,&max_line,buffer); + } + /* if file is empty, we allocate an empty struct */ + if (!lines_buffer) { + /* create the end of the list */ + lines_buffer=MemMalloc(sizeof(char*)); + lines_buffer[0]=NULL; + } + + /* End of file, we close the handle */ + logdebug("%d line(s) read from %s",FileGetCPT(last_id),filename); + FileClose(last_id); + + return lines_buffer; +} + +#define FileReadClose(filename) _internal_fgetsmulti(filename,CLOSE_READING) +#define FileReadLine(filename) _internal_fgetsmulti(filename,RAW_READING) + +long FileReadPos(char *filename) +{ + #undef FUNC + #define FUNC "FileReadPos" + + FILE *last_id; + + last_id=FileOpen(filename,"r"); + return ftell(last_id); +} + +/*** + + FileWriteLine function + + input: + - filename + - a buffer with the line to write + + the function do not close the file until a NULL buffer is sent. + It prevents from too much write flushes + + you can use it with many files simultaneously but do not forget + to close your files if you use this function in a loop of filenames + or the system will warn you +*/ + +void FileWriteLine(char *filename, char *buffer) +{ + #undef FUNC + #define FUNC "FileWriteLine" + FILE *last_id=NULL; + + last_id=FileOpen(filename,"a+"); + + if (buffer!=NULL) + { + fputs(buffer,last_id); + FileIncCPT(last_id); + } + else + { + /* NULL buffer sent, this means End of file, we close the handle */ + //logdebug("%d line(s) written to %s",FileGetCPT(last_id),filename); + FileClose(last_id); + } +} +void FileWriteLines(char *filename, char **buffer) +{ + #undef FUNC + #define FUNC "FileWriteLines" + FILE *last_id=NULL; + int i; + + last_id=FileOpen(filename,"a+"); + for (i=0;buffer[i];i++) { + fputs(buffer[i],last_id); + FileIncCPT(last_id); + } + //logdebug("%d line(s) written to %s",FileGetCPT(last_id),filename); + FileClose(last_id); +} + +/*** + FileReadBinary function + + read n bytes into buffer + return number of byte really read + + as other File functions, you can use it with many files simultaneously +*/ +int FileReadBinary(char *filename,char *data,int n) +{ + #undef FUNC + #define FUNC "FileReadBinary" + FILE *last_id=NULL; + int nn; + + last_id=FileOpen(filename,"rb"); + + if (data==NULL) + { + FileClose(last_id); + return 0; + } + + nn=fread(data,1,n,last_id); + //printf("%d bytes lus\n",nn); + FileAddCPT(last_id,nn); + if (nn!=n) + { + /* if eof is set, this is not an error */ + if (feof(last_id)) + { + //logdebug("%d byte(s) read from %s",FileGetCPT(last_id),filename); + } + else + if (ferror(last_id)) + { + if (!nn) { + logerr("cannot read %s",filename); + } + else { + logerr("error %d bytes were read during reading of %d bytes of %s",nn,n,filename); + } + exit(ABORT_ERROR); + } + else + { + logerr("error during read of %s (but no error neither eof flag set)",filename); + exit(INTERNAL_ERROR); + } + FileClose(last_id); + } + return nn; +} + +/*** + FileWriteBinary function + + write n bytes from buffer to file + return number of byte really written + + as other File functions, you can use it with many files simultaneously +*/ +int FileWriteBinary(char *filename,char *data,int n) +{ + #undef FUNC + #define FUNC "FileWriteBinary" + FILE *last_id=NULL; + int nn; + + #ifdef OS_WIN + last_id=FileOpen(filename,"w"); + #else + last_id=FileOpen(filename,"a+"); + #endif + if (data!=NULL) + { + #ifdef OS_WIN + int sr; + sr=_setmode(_fileno(last_id), _O_BINARY ); + if (sr==-1) { + logerr("FATAL: cannot set binary mode for writing"); + exit(ABORT_ERROR); + } + #endif + nn=fwrite(data,1,n,last_id); + FileAddCPT(last_id,nn); + /* we must always write the same amount of data */ + if (n!=nn) + { + if (ferror(last_id)) + { + if (!nn) { + logerr("cannot write %s",filename); + logerr("%s",strerror(errno)); + } + else{ + logerr("error during write of %s (%d byte(s))",filename,FileGetCPT(last_id)); + } + exit(ABORT_ERROR); + } + else + { + logerr("error during write of %s (but no error neither eof flag set) %d byte(s) written",filename,FileGetCPT(last_id)); + exit(INTERNAL_ERROR); + } + } + } + else + { + /* NULL buffer sent, this means End of file, we close the handle */ + //logdebug("%d byte(s) written to %s",FileGetCPT(last_id),filename); + FileClose(last_id); + } + return nn; +} +/*** macro to close binary files */ +#define FileWriteLineClose(filename) FileWriteLine(filename,NULL) +#define FileReadBinaryClose(filename) FileReadBinary(filename,NULL,0) +#define FileWriteBinaryClose(filename) FileWriteBinary(filename,NULL,0) + +/*** + FileGetStat + + input: filename + return the stat structure of a given file +*/ +struct stat *FileGetStat(char *filename) +{ + #undef FUNC + #define FUNC "FileGetStat" + struct stat *filestat; +#ifdef OS_WIN + struct _stat winstat; +#endif + + if (!filename) + { + logerr("filename must not be NULL"); + exit(ABORT_ERROR); + } + /* check after by the system but... */ + if (strnlen(filename,PATH_MAX)==PATH_MAX) + { + logerr("cannot open this file because the argument size is bigger than PATH_MAX (%d)",PATH_MAX); + logerr("[%s]",filename); + exit(ABORT_ERROR); + } + + filestat=MemMalloc(sizeof(struct stat)); + memset(filestat,0,sizeof(struct stat)); +#ifdef OS_WIN + if (_stat(filename,&winstat)!=0) +#else + if (stat(filename,filestat) && errno!=ENOENT) +#endif + { + logerr("stat %s failed",filename); + switch (errno) + { + case EACCES:logerr("Search permission is denied for one of the directories in the path prefix of path.");break; + case EBADF:logerr("filedes is bad.");break; + case EFAULT:logerr("Bad address.");break; + //case ELOOP:logerr("Too many symbolic links encountered while traversing the path.");break; + case ENAMETOOLONG:logerr("File name too long.");break; + case ENOMEM:logerr("Out of memory (i.e. kernel memory).");break; + case ENOTDIR:logerr("A component of the path is not a directory.");break; + default:logerr("Unknown error %d during stat: %s",errno,strerror(errno)); + } + exit(ABORT_ERROR); + } +#ifdef OS_WIN + filestat->st_size=winstat.st_size; + filestat->st_mode=winstat.st_mode; + filestat->st_atime=winstat.st_atime; /* last access */ + filestat->st_mtime=winstat.st_mtime; /* last modification */ + filestat->st_ctime=winstat.st_ctime; /* time of creation */ +#endif + return filestat; +} + +/*** + FileGetSize + + input: filename + output: the size in bytes of the file +*/ +long long FileGetSize(char *filename) +{ + #undef FUNC + #define FUNC "FileGetSize" + struct stat *filestat; + long long nn; + + filestat=FileGetStat(filename); + nn=filestat->st_size; + MemFree(filestat); + //logdebug("size of %s = %d (%dkb)",filename,nn,nn/1024); + return nn; +} + +/*** + * append a string + * return the number of char appened + */ +int strappend(char *Adst, char *Asrc) +{ + int Lcpt=0; + + /* must be at the end to concat */ + while (*Adst) { + Adst++; + } + + /* concat and count */ + while (*Asrc) { + *Adst++=*Asrc++; + Lcpt++; + } + *Adst=0; + + return Lcpt; +} + +char * TxtTrimEnd(char *in_str) +{ + #undef FUNC + #define FUNC "TxtTrimEnd" + + char *curs; + char *space=NULL; + + curs=in_str; + /* read the string and save the first space position, unfollowed by another character */ + while (*curs) { + //if (*curs==' ' || *curs==0x0D || *curs==0x0A || *curs=='\t') { + /* this include tab, space, line feed, carriage return, ...*/ + if (*curs<=' ') { + if (!space) { + space=curs; + } + } else { + space=NULL; + } + curs++; + } + if (space) { + *space=0; + } + + return in_str; +} + +int LookForFile(char *filename, char *dirname) +{ + #undef FUNC + #define FUNC "LookForFile" + + char fullpath[PATH_MAX+1]; + int pathlen; + + /* checked by DirReadEntry but it is more convenient to have an error inside this function */ + if (!filename) + { + logerr("You must specify at least a filename with the path, or a filename and a dirname. Filename cannot be NULL!"); + exit(INTERNAL_ERROR); + } + + pathlen=strnlen(filename,PATH_MAX); + if (pathlen==PATH_MAX) + { + logerr("cannot look for this file or directory because the argument size is bigger than PATH_MAX (%d)",PATH_MAX); + exit(ABORT_ERROR); + } + + if (!dirname) { +#ifdef OS_WIN + if (_access(filename,0)==0) return 1; else return 0; +#else + if (access(filename,F_OK)!=-1) return 1; else return 0; +#endif + } else { + pathlen+=strnlen(dirname,PATH_MAX-pathlen); + if (pathlen>=PATH_MAX-1) + { + logerr("cannot look for this file or directory because the full path size is bigger than PATH_MAX (%d)",PATH_MAX); + exit(ABORT_ERROR); + } + sprintf(fullpath,"%s/%s",dirname,filename); +#ifdef OS_WIN + if (_access(fullpath,0)==0) return 1; else return 0; +#else + if (access(fullpath,F_OK)!=-1) return 1; else return 0; +#endif + } +} + +#define FileExists(zefile) LookForFile(zefile,NULL) + +int _internal_do_remove(char *zename, char *zetype) +{ + #undef FUNC + #define FUNC "_do_remove" + + if (zename==NULL) + { + logerr("the argument cannot be NULL"); + exit(INTERNAL_ERROR); + } + if (strnlen(zename,PATH_MAX)==PATH_MAX) + { + logerr("cannot remove this file or directory because the argument size is bigger than PATH_MAX (%d)",PATH_MAX); + exit(ABORT_ERROR); + } + + if (remove(zename)) + { + switch (errno) + { + case EACCES:logerr("Write permission is denied for the directory from which the %s [%s] is to be removed, or the directory has the sticky bit set and you do not own the file.",zetype,zename);break; + case EBUSY:logerr("This error indicates that the %s [%s] is being used by the system in such a way that it can't be unlinked. For example, you might see this error if the file name specifies the root directory or a mount point for a file system.",zetype,zename);break; + case ENOENT:logerr("The %s named [%s] to be deleted doesn't exist.",zetype,zename);break; + case EPERM:logerr("On some systems unlink cannot be used to delete the name of a directory [%s], or at least can only be used this way by a privileged user. To avoid such problems, use rmdir to delete directories.",zename);break; + case EROFS:logerr("The directory containing the %s named [%s] to be deleted is on a read-only file system and can't be modified.",zetype,zename);break; + case ENOTEMPTY:logerr("The directory [%s] to be deleted is not empty.",zename);break; + default:logerr("Unknown error %d during remove [%s]: %s",errno,zename,strerror(errno)); + } + exit(ABORT_ERROR); + } + //logdebug("%s deleted",zename); + return 0; +} + +#define FileRemove(filename) _internal_do_remove(filename,"file") + +void FileRemoveIfExists(char *filename) +{ + #undef FUNC + #define FUNC "FileRemoveIfExists" + if (FileExists(filename)) + FileRemove(filename); +} + + +#undef __FILENAME__ diff --git a/tools/rasm_src/rasm.h b/tools/rasm_src/rasm.h new file mode 100644 index 0000000..bfac332 --- /dev/null +++ b/tools/rasm_src/rasm.h @@ -0,0 +1,26 @@ + +struct s_debug_error { + char *filename; + int line; + char *msg; + int lenmsg,lenfilename; +}; +struct s_debug_symbol { + char *name; + int v; +}; +struct s_rasm_info { + struct s_debug_error *error; + int nberror,maxerror; + struct s_debug_symbol *symbol; + int nbsymbol,maxsymbol; +}; + + +extern "C" { +int RasmAssemble(const char *datain, int lenin, unsigned char **dataout, int *lenout); +int RasmAssembleInfo(const char *datain, int lenin, unsigned char **dataout, int *lenout, struct s_rasm_info **debug); +void RasmFreeInfoStruct(struct s_rasm_info *debug); +}; + + diff --git a/tools/rasm_src/rasm_v0119.c b/tools/rasm_src/rasm_v0119.c new file mode 100644 index 0000000..6593392 --- /dev/null +++ b/tools/rasm_src/rasm_v0119.c @@ -0,0 +1,17316 @@ +#define PROGRAM_NAME "RASM" +#define PROGRAM_VERSION "0.119" +#define PROGRAM_DATE "xx/12/2019" +#define PROGRAM_COPYRIGHT "© 2017 BERGE Edouard / roudoudou from Resistance" + +#define RASM_VERSION PROGRAM_NAME" v"PROGRAM_VERSION" (build "PROGRAM_DATE")" +#define RASM_SNAP_VERSION PROGRAM_NAME" v"PROGRAM_VERSION + +#define TRACE_GENERALE 0 +#define TRACE_PREPRO 0 +#define TRACE_ASSEMBLE 0 +#define TRACE_COMPUTE_EXPRESSION 0 +#define TRACE_HEXBIN 0 +#define TRACE_MAKEAMSDOSREAL 0 +#define TRACE_STRUCT 0 +#define TRACE_EDSK 0 + + + +/*** +Rasm (roudoudou assembler) Z80 assembler + +doc & latest official release at: http://www.cpcwiki.eu/forum/programming/rasm-z80-assembler-in-beta/ + +You may send requests/bugs in the same topic + +----------------------------------------------------------------------------------------------------- +This software is using MIT "expat" license + +« Copyright © BERGE Edouard (roudoudou) + +Permission is hereby granted, free of charge,to any person obtaining a copy of this software +and associated documentation/source files of RASM, to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. +The Software is provided "as is", without warranty of any kind, express or implied, +including but not limited to the warranties of merchantability, fitness for a particular +purpose and noninfringement. In no event shall the authors or copyright holders be liable for +any claim, damages or other liability, whether in an action of contract, tort or otherwise, +arising from, out of or in connection with the software or the use or other dealings in the +Software. » +----------------------------------------------------------------------------------------------------- +Linux compilation with GCC or Clang: +cc rasm_v0116.c -O2 -lm -lrt -march=native -o rasm +strip rasm + +Windows compilation with Visual studio: +cl.exe rasm_v0116.c -O2 -Ob3 + +pure MS-DOS 32 bits compilation with Watcom: +wcl386 rasm_v0116.c -6r -6s -fp6 -d0 -k4000000 -ox /bt=DOS /l=dos4g + +MorphOS compilation (ixemul): +ppc-morphos-gcc-5 -O2 -c -o rasm rasm_v0116.c +strip rasm + +MacOS compilation: +cc rasm_v0116.c -O2 -lm -march=native -o rasm + +*/ + +#ifdef __WATCOMC__ +#define OS_WIN 1 +#endif + +#ifdef _WIN32 +#define OS_WIN 1 +#endif + +#ifdef _WIN64 +#define OS_WIN 1 +#endif + +#ifndef RDD + /* public lib */ + #include"minilib.h" +#else + /* private dev lib wont be published */ + #include"../tools/library.h" + #define TxtSplitWithChar _internal_TxtSplitWithChar +#endif + +#ifndef NO_3RD_PARTIES +#define __FILENAME__ "3rd parties" +/* 3rd parties compression */ +#include"zx7.h" +#include"lz4.h" +#include"exomizer.h" +#endif + +#ifdef __MORPHOS__ +/* Add standard version string to executable */ +const char __attribute__((section(".text"))) ver_version[]={ "\0$VER: "PROGRAM_NAME" "PROGRAM_VERSION" ("PROGRAM_DATE") "PROGRAM_COPYRIGHT"" }; +#endif + +#undef __FILENAME__ +#define __FILENAME__ "rasm.c" + +#ifndef OS_WIN +#define KNORMAL "\x1B[0m" +#define KERROR "\x1B[31m" +#define KAYGREEN "\x1B[32m" +#define KWARNING "\x1B[33m" +#define KBLUE "\x1B[34m" +#define KVERBOSE "\x1B[36m" +#define KIO "\x1B[97m" +#else +#define KNORMAL "" +#define KERROR "Error: " +#define KAYGREEN "" +#define KWARNING "Warning: " +#define KBLUE "" +#define KVERBOSE "" +#define KIO "" +#endif + +/******************************************************************* + c o m m a n d l i n e p a r a m e t e r s +*******************************************************************/ +enum e_dependencies_type { +E_DEPENDENCIES_NO=0, +E_DEPENDENCIES_LIST, +E_DEPENDENCIES_MAKE +}; + +struct s_parameter { + char **labelfilename; + char *filename; + char *outputfilename; + int automatic_radix; + int export_local; + int export_var; + int export_equ; + int export_sym; + int export_multisym; + int export_tape; + char *flexible_export; + int export_sna; + int export_snabrk; + int export_brk; + int nowarning; + int checkmode; + int dependencies; + int maxerr; + int macrovoid; + int extended_error; + int edskoverwrite; + float rough; + int as80,dams; + int v2; + int warn_unused; + char *symbol_name; + char *binary_name; + char *cartridge_name; + char *snapshot_name; + char *tape_name; + char *breakpoint_name; + char **symboldef; + int nsymb,msymb; + char **pathdef; + int npath,mpath; +}; + + + +/******************************************************************* + c o m p u t e o p e r a t i o n s f o r c a l c u l a t o r +*******************************************************************/ + +enum e_compute_operation_type { +E_COMPUTE_OPERATION_PUSH_DATASTC=0, +E_COMPUTE_OPERATION_OPEN=1, +E_COMPUTE_OPERATION_CLOSE=2, +E_COMPUTE_OPERATION_ADD=3, +E_COMPUTE_OPERATION_SUB=4, +E_COMPUTE_OPERATION_DIV=5, +E_COMPUTE_OPERATION_MUL=6, +E_COMPUTE_OPERATION_AND=7, +E_COMPUTE_OPERATION_OR=8, +E_COMPUTE_OPERATION_MOD=9, +E_COMPUTE_OPERATION_XOR=10, +E_COMPUTE_OPERATION_NOT=11, +E_COMPUTE_OPERATION_SHL=12, +E_COMPUTE_OPERATION_SHR=13, +E_COMPUTE_OPERATION_BAND=14, +E_COMPUTE_OPERATION_BOR=15, +E_COMPUTE_OPERATION_LOWER=16, +E_COMPUTE_OPERATION_GREATER=17, +E_COMPUTE_OPERATION_EQUAL=18, +E_COMPUTE_OPERATION_NOTEQUAL=19, +E_COMPUTE_OPERATION_LOWEREQ=20, +E_COMPUTE_OPERATION_GREATEREQ=21, +/* math functions */ +E_COMPUTE_OPERATION_SIN=22, +E_COMPUTE_OPERATION_COS=23, +E_COMPUTE_OPERATION_INT=24, +E_COMPUTE_OPERATION_FLOOR=25, +E_COMPUTE_OPERATION_ABS=26, +E_COMPUTE_OPERATION_LN=27, +E_COMPUTE_OPERATION_LOG10=28, +E_COMPUTE_OPERATION_SQRT=29, +E_COMPUTE_OPERATION_ASIN=30, +E_COMPUTE_OPERATION_ACOS=31, +E_COMPUTE_OPERATION_ATAN=32, +E_COMPUTE_OPERATION_EXP=33, +E_COMPUTE_OPERATION_LOW=34, +E_COMPUTE_OPERATION_HIGH=35, +E_COMPUTE_OPERATION_PSG=36, +E_COMPUTE_OPERATION_RND=37, +E_COMPUTE_OPERATION_FRAC=38, +E_COMPUTE_OPERATION_CEIL=39, +E_COMPUTE_OPERATION_GET_R=40, +E_COMPUTE_OPERATION_GET_V=41, +E_COMPUTE_OPERATION_GET_B=42, +E_COMPUTE_OPERATION_SET_R=43, +E_COMPUTE_OPERATION_SET_V=44, +E_COMPUTE_OPERATION_SET_B=45, +E_COMPUTE_OPERATION_END=46 +}; + +struct s_compute_element { +enum e_compute_operation_type operator; +double value; +int priority; +}; + +struct s_compute_core_data { + /* evaluator v3 may be recursive */ + char *varbuffer; + int maxivar; + struct s_compute_element *tokenstack; + int maxtokenstack; + struct s_compute_element *operatorstack; + int maxoperatorstack; +}; + +/*********************************************************** + w a v h e a d e r f o r a u d i o i m p o r t +***********************************************************/ +struct s_wav_header { +unsigned char ChunkID[4]; +unsigned char ChunkSize[4]; +unsigned char Format[4]; +unsigned char SubChunk1ID[4]; +unsigned char SubChunk1Size[4]; +unsigned char AudioFormat[2]; +unsigned char NumChannels[2]; +unsigned char SampleRate[4]; +unsigned char ByteRate[4]; +unsigned char BlockAlign[2]; +unsigned char BitsPerSample[2]; +unsigned char SubChunk2ID[4]; +unsigned char SubChunk2Size[4]; +}; + +enum e_audio_sample_type { +AUDIOSAMPLE_SMP, +AUDIOSAMPLE_SM2, +AUDIOSAMPLE_SM4, +AUDIOSAMPLE_DMA, +AUDIOSAMPLE_END +}; + +/*********************************************************************** + e x p r e s s i o n t y p e s f o r d e l a y e d w r i t e +***********************************************************************/ +enum e_expression { + E_EXPRESSION_J8, /* relative 8bits jump */ + E_EXPRESSION_0V8, /* 8 bits value to current adress */ + E_EXPRESSION_V8, /* 8 bits value to current adress+1 */ + E_EXPRESSION_V16, /* 16 bits value to current adress+1 */ + E_EXPRESSION_V16C, /* 16 bits value to current adress+1 */ + E_EXPRESSION_0V16, /* 16 bits value to current adress */ + E_EXPRESSION_0V32, /* 32 bits value to current adress */ + E_EXPRESSION_0VR, /* AMSDOS real value (5 bytes) to current adress */ + E_EXPRESSION_IV8, /* 8 bits value to current adress+2 */ + E_EXPRESSION_IV81, /* 8 bits value+1 to current adress+2 */ + E_EXPRESSION_3V8, /* 8 bits value to current adress+3 used with LD (IX+n),n */ + E_EXPRESSION_IV16, /* 16 bits value to current adress+2 */ + E_EXPRESSION_RST, /* the offset of RST is translated to the opcode */ + E_EXPRESSION_IM, /* the interrupt mode is translated to the opcode */ + E_EXPRESSION_RUN, /* delayed RUN value */ + E_EXPRESSION_ZXRUN, /* delayed RUN value for ZX snapshot */ + E_EXPRESSION_ZXSTACK /* delayed STACK value for ZX snapshot */ +}; + +struct s_expression { + char *reference; /* backup when used inside loop (or macro?) */ + int iw; /* word index in the main wordlist */ + int o; /* offset de depart 0, 1 ou 3 selon l'opcode */ + int ptr; /* offset courant pour calculs relatifs */ + int wptr; /* where to write the result */ + enum e_expression zetype; /* type of delayed write */ + int lz; /* lz zone */ + int ibank; /* ibank of expression */ + int iorgzone; /* org of expression */ +}; + +struct s_expr_dico { + char *name; + int crc; + int autorise_export; + double v; + int used; + int iw; +}; + +struct s_label { + char *name; /* is alloced for local repeat or struct OR generated global -> in this case iw=-1 */ + int iw; /* index of the word of label name */ + int crc; /* crc of the label name */ + int ptr; /* "physical" adress */ + int lz; /* is the label in a crunched section (or after)? */ + int iorgzone; /* org of label */ + int ibank; /* current CPR bank / always zero in classic mode */ + int local; + /* errmsg */ + int fileidx; + int fileline; + int autorise_export,backidx; + int used; +}; + +struct s_alias { + char *alias; + char *translation; + int crc,len,autorise_export; + int iw; + int used; +}; + +struct s_ticker { + char *varname; + int crc; + long nopstart; + long tickerstart; +}; + +/*********************************************************************** + m e r k e l t r e e s f o r l a b e l, v a r, a l i a s +***********************************************************************/ +struct s_crclabel_tree { + struct s_crclabel_tree *radix[256]; + struct s_label *label; + int nlabel,mlabel; +}; +struct s_crcdico_tree { + struct s_crcdico_tree *radix[256]; + struct s_expr_dico *dico; + int ndico,mdico; +}; +struct s_crcused_tree { + struct s_crcused_tree *radix[256]; + char **used; + int nused,mused; +}; +struct s_crcstring_tree { + struct s_crcstring_tree *radix[256]; + char **text; + int ntext,mtext; + char **replace; + int nreplace,mreplace; +}; +/************************************************* + m e m o r y s e c t i o n +*************************************************/ +struct s_lz_section { + int iw; + int memstart,memend; + int lzversion; /* 4 -> LZ4 / 7 -> ZX7 / 48 -> LZ48 / 49 -> LZ49 / 8 -> Exomizer */ + int iorgzone; + int ibank; + /* idx backup */ + int iexpr; + int ilabel; +}; + +struct s_orgzone { + int ibank,protect; + int memstart,memend; + int ifile,iline; + int nocode; +}; + +/************************************************** + i n c b i n s t o r a g e +**************************************************/ +struct s_hexbin { + unsigned char *data; + int datalen,rawlen; + char *filename; + int crunch; +}; + +/************************************************** + e d s k m a n a g e m e n t +**************************************************/ +struct s_edsk_sector_global_struct { +unsigned char track; +unsigned char side; +unsigned char id; +unsigned char size; +unsigned char st1; +unsigned char st2; +unsigned short int length; +unsigned char *data; +}; + +struct s_edsk_track_global_struct { +int sectornumber; +/* information purpose */ +int sectorsize; +int gap3length; +int fillerbyte; +int datarate; +int recordingmode; +struct s_edsk_sector_global_struct *sector; +}; + +struct s_edsk_global_struct { +int tracknumber; +int sidenumber; +int tracksize; /* DSK legacy */ +struct s_edsk_track_global_struct *track; +}; + +struct s_edsk_wrapper_entry { +unsigned char user; +unsigned char filename[11]; +unsigned char subcpt; +unsigned char extendcounter; +unsigned char reserved; +unsigned char rc; +unsigned char blocks[16]; +}; + +struct s_edsk_wrapper { +char *edsk_filename; +struct s_edsk_wrapper_entry entry[64]; +int nbentry; +unsigned char blocks[178][1024]; /* DATA format */ +int face; +}; + +struct s_save { + int ibank; + int ioffset; + int isize; + int iw,irun; + int amsdos,hobeta; + int tape,dsk,face,iwdskname; +}; + + +/******************** + L O O P S +********************/ + +enum e_loop_style { +E_LOOPSTYLE_REPEATN, +E_LOOPSTYLE_REPEATUNTIL, +E_LOOPSTYLE_WHILE +}; + +struct s_repeat { + int start; + int cpt; + int value; + int maxim; + int repeat_counter; + char *repeatvar; + int repeatcrc; +}; + +struct s_whilewend { + int start; + int cpt; + int value; + int maxim; + int while_counter; +}; + +struct s_switchcase { + int refval; + int execute; + int casematch; +}; + +struct s_repeat_index { + int ifile; + int ol,oidx; + int cl,cidx; +}; + + +enum e_ifthen_type { +E_IFTHEN_TYPE_IF=0, +E_IFTHEN_TYPE_IFNOT=1, +E_IFTHEN_TYPE_IFDEF=2, +E_IFTHEN_TYPE_IFNDEF=3, +E_IFTHEN_TYPE_ELSE=4, +E_IFTHEN_TYPE_ELSEIF=5, +E_IFTHEN_TYPE_IFUSED=6, +E_IFTHEN_TYPE_IFNUSED=7, +E_IFTHEN_TYPE_END +}; + +struct s_ifthen { + char *filename; + int line,v; + enum e_ifthen_type type; +}; + +/************************************************** + w o r d p r o c e s s i n g +**************************************************/ +struct s_wordlist { + char *w; + int l,t,e; /* e=1 si egalite dans le mot */ + int ifile; +}; + +struct s_macro { + char *mnemo; + int crc; + /* une macro concatene des chaines et des parametres */ + struct s_wordlist *wc; + int nbword,maxword; + /**/ + char **param; + int nbparam; +}; + +struct s_macro_position { + int start,end,value; +}; + +/* preprocessing only */ +struct s_macro_fast { + char *mnemo; + int crc; +}; + +struct s_math_keyword { + char *mnemo; + int crc; + enum e_compute_operation_type operation; +}; + +struct s_expr_word { + char *w; + int aw; + int op; + int comma; + int fct; + double v; +}; + +struct s_listing { + char *listing; + int ifile; + int iline; +}; + +enum e_tagtranslateoption { +E_TAGOPTION_NONE=0, +E_TAGOPTION_REMOVESPACE=1, +E_TAGOPTION_PRESERVE=2 +}; + +#ifdef RASM_THREAD +struct s_rasm_thread { + pthread_t thread; + int lz; + unsigned char *datain; + int datalen; + unsigned char *dataout; + int lenout; + int status; +}; +#endif + + +/********************************************************* + S N A P S H O T E X P O R T +*********************************************************/ +/* extension 4Mo = 256 slots + 4 slots 64K de RAM par défaut => 260 */ + +#define BANK_MAX_NUMBER 260 + +struct s_snapshot_symbol { + unsigned char size; + unsigned char name[256]; + unsigned char reserved[6]; + unsigned char bigendian_adress[2]; +}; + + +struct s_zxsnapshot { + + unsigned int run; + unsigned int stack; +}; + +struct s_snapshot { + char idmark[8]; + char unused1[8]; + unsigned char version; /* 3 */ + struct { + struct { + unsigned char F; + unsigned char A; + unsigned char C; + unsigned char B; + unsigned char E; + unsigned char D; + unsigned char L; + unsigned char H; + }general; + unsigned char R; + unsigned char regI; /* I incompatible with tgmath.h */ + unsigned char IFF0; + unsigned char IFF1; + unsigned char LX; + unsigned char HX; + unsigned char LY; + unsigned char HY; + unsigned char LSP; + unsigned char HSP; + unsigned char LPC; + unsigned char HPC; + unsigned char IM; /* 0,1,2 */ + struct { + unsigned char F; + unsigned char A; + unsigned char C; + unsigned char B; + unsigned char E; + unsigned char D; + unsigned char L; + unsigned char H; + }alternate; + }registers; + + struct { + unsigned char selectedpen; + unsigned char palette[17]; + unsigned char multiconfiguration; + }gatearray; + unsigned char ramconfiguration; + struct { + unsigned char selectedregister; + unsigned char registervalue[18]; + }crtc; + unsigned char romselect; + struct { + unsigned char portA; + unsigned char portB; + unsigned char portC; + unsigned char control; + }ppi; + struct { + unsigned char selectedregister; + unsigned char registervalue[16]; + }psg; + unsigned char dumpsize[2]; /* 64 then use extended memory chunks */ + + unsigned char CPCType; /* 0=464 / 1=664 / 2=6128 / 4=6128+ / 5=464+ / 6=GX4000 */ + unsigned char interruptnumber; + unsigned char multimodebytes[6]; + unsigned char unused2[0x9C-0x75]; + + /* offset #9C */ + struct { + unsigned char motorstate; + unsigned char physicaltrack; + }fdd; + unsigned char unused3[3]; + unsigned char printerstrobe; + unsigned char unused4[2]; + struct { + unsigned char model; /* 0->4 */ + unsigned char unused5[4]; + unsigned char HCC; + unsigned char unused; + unsigned char CLC; + unsigned char RLC; + unsigned char VTC; + unsigned char HSC; + unsigned char VSC; + unsigned short int flags; + }crtcstate; + unsigned char vsyncdelay; + unsigned char interruptscanlinecounter; + unsigned char interruptrequestflag; + unsigned char unused6[0xFF-0xB5+1]; +}; + +struct s_snapshot_chunks { + unsigned char chunkname[4]; /* MEM1 -> MEM8 */ + unsigned int chunksize; +}; + +struct s_breakpoint { + int address; + int bank; +}; + + +/********************************* + S T R U C T U R E S +*********************************/ +enum e_rasmstructfieldtype { +E_RASMSTRUCTFIELD_BYTE, +E_RASMSTRUCTFIELD_WORD, +E_RASMSTRUCTFIELD_LONG, +E_RASMSTRUCTFIELD_REAL, +E_RASMSTRUCTFIELD_END +}; +struct s_rasmstructfield { + char *fullname; + char *name; + int offset; + int size; + int crc; + /* filler */ + unsigned char *data; + int idata,mdata; + enum e_rasmstructfieldtype zetype; +}; + +struct s_rasmstruct { + char *name; + int crc; + int size; + int ptr; + int nbelem; + /* fields */ + struct s_rasmstructfield *rasmstructfield; + int irasmstructfield,mrasmstructfield; +}; + +/********************************* + D E B U G +*********************************/ +struct s_debug_error { + char *filename; + int line; + char *msg; + int lenmsg,lenfilename; +}; +struct s_debug_symbol { + char *name; + int v; +}; +struct s_rasm_info { + struct s_debug_error *error; + int nberror,maxerror; + struct s_debug_symbol *symbol; + int nbsymbol,maxsymbol; +}; + +/******************************************* + G L O B A L S T R U C T +*******************************************/ +struct s_assenv { + /* current memory */ + int maxptr; + /* CPR memory */ + unsigned char **mem; + int iwnamebank[BANK_MAX_NUMBER]; + int nbbank,maxbank; + int forcetape,forcezx,forcecpr,bankmode,activebank,amsdos,forcesnapshot,packedbank; + struct s_snapshot snapshot; + struct s_zxsnapshot zxsnapshot; + int bankset[BANK_MAX_NUMBER>>2]; /* 64K selected flag */ + int bankused[BANK_MAX_NUMBER]; /* 16K selected flag */ + int bankgate[BANK_MAX_NUMBER+1]; + int setgate[BANK_MAX_NUMBER+1]; + int rundefined; + /* parsing */ + struct s_wordlist *wl; + int nbword; + int idx,stage; + char *label_filename; + int label_line; + char **filename; + int ifile,maxfile; + int nberr,flux; + int fastmatch[256]; + unsigned char charset[256]; + int maxerr,extended_error,nowarning; + /* ORG tracking */ + int codeadr,outputadr,nocode; + int codeadrbackup,outputadrbackup; + int minadr,maxadr; + struct s_orgzone *orgzone; + int io,mo; + /* Struct */ + struct s_rasmstruct *rasmstruct; + int irasmstruct,mrasmstruct; + int getstruct; + int backup_outputadr,backup_codeadr; + char *backup_filename; + int backup_line; + struct s_rasmstruct *rasmstructalias; + int irasmstructalias,mrasmstructalias; + /* expressions */ + struct s_expression *expression; + int ie,me; + int maxam,as80,dams; + float rough; + struct s_compute_core_data *computectx,ctx1,ctx2; + struct s_crcstring_tree stringtree; + /* label */ + struct s_label *label; + int il,ml; + struct s_crclabel_tree labeltree; /* fast label access */ + char *module; + int modulen; + struct s_breakpoint *breakpoint; + int ibreakpoint,maxbreakpoint; + char *lastgloballabel; + char *lastsuperglobal; + int lastgloballabellen, lastglobalalloc; + /* repeat */ + struct s_repeat *repeat; + int ir,mr; + /* while/wend */ + struct s_whilewend *whilewend; + int iw,mw; + /* if/then/else */ + //int *ifthen; + struct s_ifthen *ifthen; + int ii,mi; + /* switch/case */ + struct s_switchcase *switchcase; + int isw,msw; + /* expression dictionnary */ + struct s_expr_dico *dico; + int idic,mdic; + struct s_crcdico_tree dicotree; /* fast dico access */ + struct s_crcused_tree usedtree; /* fast used access */ + /* ticker */ + struct s_ticker *ticker; + int iticker,mticker; + long tick,nop; + /* crunch section flag */ + struct s_lz_section *lzsection; + int ilz,mlz; + int lz,curlz; + /* macro */ + struct s_macro *macro; + int imacro,mmacro; + int macrovoid; + /* labels locaux */ + int repeatcounter,whilecounter,macrocounter; + struct s_macro_position *macropos; + int imacropos,mmacropos; + /* alias */ + struct s_alias *alias; + int ialias,malias; + /* hexbin */ + struct s_rasm_thread **rasm_thread; + int irt,mrt; + struct s_hexbin *hexbin; + int ih,mh; + char **includepath; + int ipath,mpath; + /* automates */ + char AutomateExpressionValidCharExtended[256]; + char AutomateExpressionValidCharFirst[256]; + char AutomateExpressionValidChar[256]; + char AutomateExpressionDecision[256]; + char AutomateValidLabelFirst[256]; + char AutomateValidLabel[256]; + char AutomateDigit[256]; + char AutomateHexa[256]; + struct s_compute_element AutomateElement[256]; + unsigned char psgtab[256]; + unsigned char psgfine[256]; + /* output */ + char *outputfilename; + int export_sym,export_local,export_multisym; + int export_var,export_equ; + int export_sna,export_snabrk; + int export_brk,export_tape; + int autorise_export; + char *flexible_export; + char *breakpoint_name; + char *symbol_name; + char *binary_name; + char *cartridge_name; + char *snapshot_name; + struct s_save *save; + int nbsave,maxsave; + int current_run_idx; + struct s_edsk_wrapper *edsk_wrapper; + int nbedskwrapper,maxedskwrapper; + int edskoverwrite; + int checkmode,dependencies; + int stop; + int warn_unused; + /* debug */ + struct s_rasm_info debug; + struct s_rasm_info **retdebug; + int debug_total_len; +}; + +/************************************* + D I R E C T I V E S +*************************************/ +struct s_asm_keyword { + char *mnemo; + int crc; + void (*makemnemo)(struct s_assenv *ae); +}; + +struct s_math_keyword math_keyword[]={ +{"SIN",0,E_COMPUTE_OPERATION_SIN}, +{"COS",0,E_COMPUTE_OPERATION_COS}, +{"INT",0,E_COMPUTE_OPERATION_INT}, +{"ABS",0,E_COMPUTE_OPERATION_ABS}, +{"LN",0,E_COMPUTE_OPERATION_LN}, +{"LOG10",0,E_COMPUTE_OPERATION_LOG10}, +{"SQRT",0,E_COMPUTE_OPERATION_SQRT}, +{"FLOOR",0,E_COMPUTE_OPERATION_FLOOR}, +{"ASIN",0,E_COMPUTE_OPERATION_ASIN}, +{"ACOS",0,E_COMPUTE_OPERATION_ACOS}, +{"ATAN",0,E_COMPUTE_OPERATION_ATAN}, +{"EXP",0,E_COMPUTE_OPERATION_EXP}, +{"LO",0,E_COMPUTE_OPERATION_LOW}, +{"HI",0,E_COMPUTE_OPERATION_HIGH}, +{"PSGVALUE",0,E_COMPUTE_OPERATION_PSG}, +{"RND",0,E_COMPUTE_OPERATION_RND}, +{"FRAC",0,E_COMPUTE_OPERATION_FRAC}, +{"CEIL",0,E_COMPUTE_OPERATION_CEIL}, +{"GETR",0,E_COMPUTE_OPERATION_GET_R}, +{"GETV",0,E_COMPUTE_OPERATION_GET_V}, +{"GETG",0,E_COMPUTE_OPERATION_GET_V}, +{"GETB",0,E_COMPUTE_OPERATION_GET_B}, +{"SETR",0,E_COMPUTE_OPERATION_SET_R}, +{"SETV",0,E_COMPUTE_OPERATION_SET_V}, +{"SETG",0,E_COMPUTE_OPERATION_SET_V}, +{"SETB",0,E_COMPUTE_OPERATION_SET_B}, +{"",0,-1} +}; + +#define CRC_SWITCH 0x01AEDE4A +#define CRC_CASE 0x0826B794 +#define CRC_DEFAULT 0x9A0DAC7D +#define CRC_BREAK 0xCD364DDD +#define CRC_ENDSWITCH 0x18E9FB21 + +#define CRC_ELSEIF 0xE175E230 +#define CRC_ELSE 0x3FF177A1 +#define CRC_ENDIF 0xCD5265DE +#define CRC_IF 0x4BD52507 +#define CRC_IFDEF 0x4CB29DD6 +#define CRC_UNDEF 0xCCD2FDEA +#define CRC_IFNDEF 0xD9AD0824 +#define CRC_IFNOT 0x4CCAC9F8 +#define CRC_WHILE 0xBC268FF1 +#define CRC_UNTIL 0xCC12A604 +#define CRC_MEND 0xFFFD899C +#define CRC_ENDM 0x3FF9559C +#define CRC_MACRO 0x64AA85EA +#define CRC_IFUSED 0x91752638 +#define CRC_IFNUSED 0x1B39A886 + +#define CRC_SIN 0xE1B71962 +#define CRC_COS 0xE077C55D + +#define CRC_0 0x7A98A6A8 +#define CRC_1 0x7A98A6A9 +#define CRC_2 0x7A98A6AA + + +#define CRC_NC 0x4BD52B09 +#define CRC_Z 0x7A98A6D2 +#define CRC_NZ 0x4BD52B20 +#define CRC_P 0x7A98A6C8 +#define CRC_PO 0x4BD53717 +#define CRC_PE 0x4BD5370D +#define CRC_M 0x7A98A6C5 + +/* 8 bits registers */ +#define CRC_F 0x7A98A6BE +#define CRC_I 0x7A98A6C1 +#define CRC_R 0x7A98A6CA +#define CRC_A 0x7A98A6B9 +#define CRC_B 0x7A98A6BA +#define CRC_C 0x7A98A6BB +#define CRC_D 0x7A98A6BC +#define CRC_E 0x7A98A6BD +#define CRC_H 0x7A98A6C0 +#define CRC_L 0x7A98A6C4 +/* dual naming */ +#define CRC_XH 0x4BD50718 +#define CRC_XL 0x4BD5071C +#define CRC_YH 0x4BD50519 +#define CRC_YL 0x4BD5051D +#define CRC_HX 0x4BD52718 +#define CRC_LX 0x4BD52F1C +#define CRC_HY 0x4BD52719 +#define CRC_LY 0x4BD52F1D +#define CRC_IXL 0xE19F1765 +#define CRC_IXH 0xE19F1761 +#define CRC_IYL 0xE19F1166 +#define CRC_IYH 0xE19F1162 + +/* 16 bits registers */ +#define CRC_BC 0x4BD5D2FD +#define CRC_DE 0x4BD5DF01 +#define CRC_HL 0x4BD5270C +#define CRC_IX 0x4BD52519 +#define CRC_IY 0x4BD5251A +#define CRC_SP 0x4BD5311B +#define CRC_AF 0x4BD5D4FF +/* memory convention */ +#define CRC_MHL 0xD0765F5D +#define CRC_MDE 0xD0467D52 +#define CRC_MBC 0xD05E694E +#define CRC_MIX 0xD072B76A +#define CRC_MIY 0xD072B16B +#define CRC_MSP 0xD01A876C +#define CRC_MC 0xE018210C +/* struct parsing */ +#define CRC_DEFB 0x37D15389 +#define CRC_DB 0x4BD5DEFE +#define CRC_DEFW 0x37D1539E +#define CRC_DW 0x4BD5DF13 +#define CRC_DEFI 0x37D15390 +#define CRC_DEFS 0x37D1539A +#define CRC_DS 0x4BD5DF0F +#define CRC_DEFR 0x37D15399 +#define CRC_DR 0x4BD5DF0E + +/* struct declaration use special instructions for defines */ +int ICRC_DEFB,ICRC_DEFW,ICRC_DEFI,ICRC_DEFR,ICRC_DEFS,ICRC_DB,ICRC_DW,ICRC_DR,ICRC_DS; +/* need to pre-declare var */ +extern struct s_asm_keyword instruction[]; + +/* +# base=16 +% base=2 +0-9 base=10 +A-Z variable ou fonction (cos, sin, tan, sqr, pow, mod, and, xor, mod, ...) ++*-/&^m| operateur +*/ + +#define AutomateExpressionValidCharExtendedDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_{}@+-*/~^$#%§<=>|&" +#define AutomateExpressionValidCharFirstDefinition "#%0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@${" +#define AutomateExpressionValidCharDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_{}@$" +#define AutomateValidLabelFirstDefinition ".ABCDEFGHIJKLMNOPQRSTUVWXYZ_@" +#define AutomateValidLabelDefinition "0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@{}" +#define AutomateDigitDefinition ".0123456789" +#define AutomateHexaDefinition "0123456789ABCDEF" + +#ifndef NO_3RD_PARTIES +unsigned char *LZ4_crunch(unsigned char *data, int zelen, int *retlen){ + unsigned char *lzdest=NULL; + lzdest=MemMalloc(65536); + *retlen=LZ4_compress_HC((char*)data,(char*)lzdest,zelen,65536,9); + return lzdest; +} +#endif +unsigned char *LZ48_encode_legacy(unsigned char *data, int length, int *retlength); +#define LZ48_crunch LZ48_encode_legacy +unsigned char *LZ49_encode_legacy(unsigned char *data, int length, int *retlength); +#define LZ49_crunch LZ49_encode_legacy + + +/* + * optimised reading of text file in one shot + */ +unsigned char *_internal_readbinaryfile(char *filename, int *filelength) +{ + #undef FUNC + #define FUNC "_internal_readbinaryfile" + + unsigned char *binary_data=NULL; + + *filelength=FileGetSize(filename); + binary_data=MemMalloc((*filelength)+1); + /* we try to read one byte more to close the file just after the read func */ + if (FileReadBinary(filename,(char*)binary_data,(*filelength)+1)!=*filelength) { + logerr("Cannot fully read %s",filename); + exit(INTERNAL_ERROR); + } + return binary_data; +} +char **_internal_readtextfile(char *filename, char replacechar) +{ + #undef FUNC + #define FUNC "_internal_readtextfile" + + char **lines_buffer=NULL; + unsigned char *bigbuffer; + int nb_lines=0,max_lines=0,i=0,e=0; + int file_size; + + bigbuffer=_internal_readbinaryfile(filename,&file_size); + + while (i<file_size) { + while (e<file_size && bigbuffer[e]!=0x0A) { + /* Windows de meeeeeeeerrrdde... */ + if (bigbuffer[e]==0x0D) bigbuffer[e]=replacechar; + e++; + } + if (e<file_size) e++; + if (nb_lines>=max_lines) { + max_lines=max_lines*2+10; + lines_buffer=MemRealloc(lines_buffer,(max_lines+1)*sizeof(char **)); + } + lines_buffer[nb_lines]=MemMalloc(e-i+1); + memcpy(lines_buffer[nb_lines],bigbuffer+i,e-i); + lines_buffer[nb_lines][e-i]=0; + if (0) + { + int yy; + for (yy=0;lines_buffer[nb_lines][yy];yy++) { + if (lines_buffer[nb_lines][yy]>31) printf("%c",lines_buffer[nb_lines][yy]); else printf("(0x%X)",lines_buffer[nb_lines][yy]); + } + printf("\n"); + } + nb_lines++; + i=e; + } + if (!max_lines) { + lines_buffer=MemMalloc(sizeof(char**)); + lines_buffer[0]=NULL; + } else { + lines_buffer[nb_lines]=NULL; + } + MemFree(bigbuffer); + return lines_buffer; +} + +#define FileReadLines(filename) _internal_readtextfile(filename,':') +#define FileReadLinesRAW(filename) _internal_readtextfile(filename,0x0D) +#define FileReadContent(filename,filesize) _internal_readbinaryfile(filename,filesize) + + +/*** + TxtReplace + + input: + in_str: string where replace will occur + in_substr: substring to look for + out_substr: replace substring + recurse: loop until no in_substr is found + + note: in_str MUST BE previously mallocated if out_substr is bigger than in_substr +*/ +#ifndef RDD +char *TxtReplace(char *in_str, char *in_substr, char *out_substr, int recurse) +{ + #undef FUNC + #define FUNC "TxtReplace" + + char *str_look,*m1,*m2; + char *out_str; + int sl,l1,l2,dif,cpt; + + if (in_str==NULL) + return NULL; + + sl=strlen(in_str); + l1=strlen(in_substr); + /* empty string, nothing to do except return empty string */ + if (!sl || !l1) + return in_str; + + l2=strlen(out_substr); + dif=l2-l1; + + /* replace string is small or equal in size, we dont realloc */ + if (dif<=0) + { + /* we loop while there is a replace to do */ + str_look=strstr(in_str,in_substr); + while (str_look!=NULL) + { + /* we copy the new string if his len is not null */ + if (l2) + memcpy(str_look,out_substr,l2); + /* only if len are different */ + if (l1!=l2) + { + /* we move the end of the string byte per byte + because memory locations overlap. This is + faster than memmove */ + m1=str_look+l1; + m2=str_look+l2; + while (*m1!=0) + { + *m2=*m1; + m1++;m2++; + } + /* we must copy the EOL */ + *m2=*m1; + } + /* look for next replace */ + if (!recurse) + str_look=strstr(str_look+l2,in_substr); + else + str_look=strstr(in_str,in_substr); + } + out_str=in_str; + } + else + { + /* we need to count each replace */ + cpt=0; + str_look=strstr(in_str,in_substr); + while (str_look!=NULL) + { + cpt++; + str_look=strstr(str_look+l1,in_substr); + } + /* is there anything to do? */ + if (cpt) + { + /* we realloc to a size that will fit all replaces */ + out_str=MemRealloc(in_str,sl+1+dif*cpt); + str_look=strstr(out_str,in_substr); + while (str_look!=NULL && cpt) + { + /* as the replace string is bigger we + have to move memory first from the end */ + m1=out_str+sl; + m2=m1+dif; + sl+=dif; + while (m1!=str_look+l1-dif) + { + *m2=*m1; + m1--;m2--; + } + /* then we copy the replace string (can't be NULL in this case) */ + memcpy(str_look,out_substr,l2); + + /* look for next replace */ + if (!recurse) + str_look=strstr(str_look+l2,in_substr); + else + str_look=strstr(in_str,in_substr); + + /* to prevent from naughty overlap */ + cpt--; + } + if (str_look!=NULL) + { + printf("INTERNAL ERROR - overlapping replace string (%s/%s), you can't use this one!\n",in_substr,out_substr); + exit(ABORT_ERROR); + } + } + else + out_str=in_str; + } + return out_str; +} +#endif + +#ifndef min +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) +#endif + +/* Levenshtein implementation by TheRayTracer https://gist.github.com/TheRayTracer/2644387 */ +int _internal_LevenshteinDistance(char *s, char *t) +{ + int i,j,n,m,*d; + int im,jn; + int r; + + n=strlen(s)+1; + m=strlen(t)+1; + d=malloc(n*m*sizeof(int)); + memset(d, 0, sizeof(int) * n * m); + + for (i = 1, im = 0; i < m; i++, im++) + { + for (j = 1, jn = 0; j < n; j++, jn++) + { + if (s[jn] == t[im]) + { + d[(i * n) + j] = d[((i - 1) * n) + (j - 1)]; + } + else + { + d[(i * n) + j] = min(d[(i - 1) * n + j] + 1, /* A deletion. */ + min(d[i * n + (j - 1)] + 1, /* An insertion. */ + d[(i - 1) * n + (j - 1)] + 1)); /* A substitution. */ + } + } + } + r = d[n * m - 1]; + free(d); + return r; +} + +#ifdef RASM_THREAD +/* + threads used for crunching +*/ +void _internal_ExecuteThreads(struct s_assenv *ae,struct s_rasm_thread *rasm_thread, void *(*fct)(void *)) +{ + #undef FUNC + #define FUNC "_internal_ExecuteThreads" + + pthread_attr_t attr; + void *status; + int rc; + /* launch threads */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE); + pthread_attr_setstacksize(&attr,65536); + + if ((rc=pthread_create(&image_threads[i].thread,&attr,fct,(void *)rasm_thread))) { + rasm_printf(ae,"FATAL ERROR - Cannot create thread!\n"); + exit(INTERNAL_ERROR); + } +} +void _internal_WaitForThreads(struct s_assenv *ae,struct s_rasm_thread *rasm_thread) +{ + #undef FUNC + #define FUNC "_internal_WaitForThreads" + int rc; + + if ((rc=pthread_join(rasm_thread->thread,&status))) { + rasm_printf(ae,"FATAL ERROR - Cannot wait for thread\n"); + exit(INTERNAL_ERROR); + } +} +void PushCrunchedFile(struct s_assenv *ae, unsigned char *datain, int datalen, int lz) +{ + #undef FUNC + #define FUNC "PushCrunchedFile" + + struct s_rasm_thread *rasm_thread; + + rasm_thread=MemMalloc(sizeof(struct s_rasm_thread)); + memset(rasm_thread,0,sizeof(struct s_rasm_thread)); + rasm_thread->datain=datain; + rasm_thread->datalen=datalen; + rasm_thread->lz=lz; + _internal_ExecuteThreads(ae,rasm_thread, void *(*fct)(void *)); + ObjectArrayAddDynamicValueConcat((void**)&ae->rasm_thread,&ae->irt,&ae->mrt,&rasm_thread,sizeof(struct s_rasm_thread *)); +} +void PopAllCrunchedFiles(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "PopAllCrunchedFiles" + + int i; + for (i=0;i<ae->irt;i++) { + _internal_WaitForThreads(ae,ae->rasm_thread[i]); + } +} +#endif + +void MaxError(struct s_assenv *ae); + +void rasm_printf(struct s_assenv *ae, ...) { + #undef FUNC + #define FUNC "(internal) rasm_printf" + + char *format; + va_list argptr; + + if (!ae->flux && !ae->dependencies) { + va_start(argptr,ae); + format=va_arg(argptr,char *); + vfprintf(stdout,format,argptr); + va_end(argptr); + fprintf(stdout,KNORMAL); + } +} +/*** + build the string of current line for error messages +*/ +char *rasm_getline(struct s_assenv *ae, int offset) { + #undef FUNC + #define FUNC "rasm_getline" + + static char myline[40]={0}; + int idx=0,icopy,first=1; + + while (!ae->wl[ae->idx+offset].t && idx<32) { + for (icopy=0;idx<32 && ae->wl[ae->idx+offset].w[icopy];icopy++) { + myline[idx++]=ae->wl[ae->idx+offset].w[icopy]; + } + if (!first) myline[idx++]=','; else first=0; + offset++; + } + if (idx>=32) { + strcpy(myline+29,"..."); + } else { + myline[idx++]=0; + } + + return myline; +} + +char *SimplifyPath(char *filename) { + #undef FUNC + #define FUNC "SimplifyPath" + + return filename; +#if 0 + char *pos,*repos; + int i,len; + + char *rpath; + + rpath=realpath(filename,NULL); + if (!rpath) { + printf("rpath error!\n"); + switch (errno) { + case EACCES:printf("read permission failure\n");break; + case EINVAL:printf("wrong argument\n");break; + case EIO:printf("I/O error\n");break; + case ELOOP:printf("too many symbolic links\n");break; + case ENAMETOOLONG:printf("names too long\n");break; + case ENOENT:printf("names does not exists\n");break; + case ENOMEM:printf("out of memory\n");break; + case ENOTDIR:printf("a component of the path is not a directory\n");break; + default:printf("unknown error\n");break; + } + exit(1); + } + if (strlen(rpath)<strlen(filename)) { + strcpy(filename,rpath); + } + free(rpath); + return filename; + +#ifdef OS_WIN + while ((pos=strstr(filename,"\\..\\"))!=NULL) { + repos=pos-1; + /* sequence found, looking back for '\' */ + while (repos>=filename) { + if (*repos=='\\') { + break; + } + repos--; + } + repos++; + if (repos>=filename && repos!=pos) { + len=strlen(pos)-4+1; + pos+=4; + for (i=0;i<len;i++) { + *repos=*pos; + repos++; + pos++; + } + } + if (strncmp(filename,".\\..\\",5)==0) { + repos=filename; + pos=repos+2; + for (;*repos;pos++,repos++) { + *repos=*pos; + } + *repos=0; + } + } +#else +printf("*************\nfilename=[%s]\n",filename); + while ((pos=strstr(filename,"/../"))!=NULL) { + repos=pos-1; + while (repos>=filename) { + if (*repos=='/') { + break; + } + repos--; + } + repos++; + if (repos>=filename && repos!=pos) { + len=strlen(pos)-4+1; + pos+=4; + for (i=0;i<len;i++) { + *repos=*pos; + repos++; + pos++; + } + } +printf("filename=[%s]\n",filename); + if (strncmp(filename,"./../",5)==0) { + repos=filename; + pos=repos+2; + for (;*repos;pos++,repos++) { + *repos=*pos; + } + *repos=0; + } +printf("filename=[%s]\n",filename); + } +#endif + return NULL; +#endif + +} + +char *GetPath(char *filename) { + #undef FUNC + #define FUNC "GetPath" + + static char curpath[PATH_MAX]; + int zelen,idx; + + zelen=strlen(filename); + +#ifdef OS_WIN + #define CURRENT_DIR ".\\" + + TxtReplace(filename,"/","\\",1); + idx=zelen-1; + while (idx>=0 && filename[idx]!='\\') idx--; + if (idx<0) { + /* pas de chemin */ + strcpy(curpath,".\\"); + } else { + /* chemin trouve */ + strcpy(curpath,filename); + curpath[idx+1]=0; + } +#else +#ifdef __MORPHOS__ + #define CURRENT_DIR "" +#else + #define CURRENT_DIR "./" +#endif + idx=zelen-1; + while (idx>=0 && filename[idx]!='/') idx--; + if (idx<0) { + /* pas de chemin */ + strcpy(curpath,CURRENT_DIR); + } else { + /* chemin trouve */ + strcpy(curpath,filename); + curpath[idx+1]=0; + } +#endif + + return curpath; +} +char *MergePath(struct s_assenv *ae,char *dadfilename, char *filename) { + #undef FUNC + #define FUNC "MergePath" + + static char curpath[PATH_MAX]; + int zelen; + +#ifdef OS_WIN + TxtReplace(filename,"/","\\",1); + + if (filename[0] && filename[1]==':' && filename[2]=='\\') { + /* chemin absolu */ + strcpy(curpath,filename); + } else if (filename[0] && filename[1]==':') { + rasm_printf(ae,KERROR"unsupported path style [%s]\n",filename); + exit(-111); + } else { + if (filename[0]=='.' && filename[1]=='\\') { + strcpy(curpath,GetPath(dadfilename)); + strcat(curpath,filename+2); + } else { + strcpy(curpath,GetPath(dadfilename)); + strcat(curpath,filename); + } + } +#else + if (filename[0]=='/') { + /* chemin absolu */ + strcpy(curpath,filename); + } else if (filename[0]=='.' && filename[1]=='/') { + strcpy(curpath,GetPath(dadfilename)); + strcat(curpath,filename+2); + } else { + strcpy(curpath,GetPath(dadfilename)); + strcat(curpath,filename); + } +#endif + + return curpath; +} + + +void InitAutomate(char *autotab, const unsigned char *def) +{ + #undef FUNC + #define FUNC "InitAutomate" + + int i; + + memset(autotab,0,256); + for (i=0;def[i];i++) { + autotab[(int)def[i]]=1; + } +} +void StateMachineResizeBuffer(char **ABuf, int idx, int *ASize) { + #undef FUNC + #define FUNC "StateMachineResizeBuffer" + + if (idx>=*ASize) { + if (*ASize<16384) { + *ASize=(*ASize)*2; + } else { + *ASize=(*ASize)+16384; + } + *ABuf=MemRealloc(*ABuf,(*ASize)+2); + } +} + +int GetCRC(char *label) +{ + #undef FUNC + #define FUNC "GetCRC" + int crc=0x12345678; + int i=0; + + while (label[i]!=0) { + crc=(crc<<9)^(crc+label[i++]); + } + return crc; +} + +int IsRegister(char *zeexpression) +{ + #undef FUNC + #define FUNC "IsRegister" + + switch (GetCRC(zeexpression)) { + case CRC_F:if (strcmp(zeexpression,"F")==0) return 1; else return 0; + case CRC_I:if (strcmp(zeexpression,"I")==0) return 1; else return 0; + case CRC_R:if (strcmp(zeexpression,"R")==0) return 1; else return 0; + case CRC_A:if (strcmp(zeexpression,"A")==0) return 1; else return 0; + case CRC_B:if (strcmp(zeexpression,"B")==0) return 1; else return 0; + case CRC_C:if (strcmp(zeexpression,"C")==0) return 1; else return 0; + case CRC_D:if (strcmp(zeexpression,"D")==0) return 1; else return 0; + case CRC_E:if (strcmp(zeexpression,"E")==0) return 1; else return 0; + case CRC_H:if (strcmp(zeexpression,"H")==0) return 1; else return 0; + case CRC_L:if (strcmp(zeexpression,"L")==0) return 1; else return 0; + case CRC_BC:if (strcmp(zeexpression,"BC")==0) return 1; else return 0; + case CRC_DE:if (strcmp(zeexpression,"DE")==0) return 1; else return 0; + case CRC_HL:if (strcmp(zeexpression,"HL")==0) return 1; else return 0; + case CRC_IX:if (strcmp(zeexpression,"IX")==0) return 1; else return 0; + case CRC_IY:if (strcmp(zeexpression,"IY")==0) return 1; else return 0; + case CRC_SP:if (strcmp(zeexpression,"SP")==0) return 1; else return 0; + case CRC_AF:if (strcmp(zeexpression,"AF")==0) return 1; else return 0; + case CRC_XH:if (strcmp(zeexpression,"XH")==0) return 1; else return 0; + case CRC_XL:if (strcmp(zeexpression,"XL")==0) return 1; else return 0; + case CRC_YH:if (strcmp(zeexpression,"YH")==0) return 1; else return 0; + case CRC_YL:if (strcmp(zeexpression,"YL")==0) return 1; else return 0; + case CRC_HX:if (strcmp(zeexpression,"HX")==0) return 1; else return 0; + case CRC_LX:if (strcmp(zeexpression,"LX")==0) return 1; else return 0; + case CRC_HY:if (strcmp(zeexpression,"HY")==0) return 1; else return 0; + case CRC_LY:if (strcmp(zeexpression,"LY")==0) return 1; else return 0; + case CRC_IXL:if (strcmp(zeexpression,"IXL")==0) return 1; else return 0; + case CRC_IXH:if (strcmp(zeexpression,"IXH")==0) return 1; else return 0; + case CRC_IYL:if (strcmp(zeexpression,"IYL")==0) return 1; else return 0; + case CRC_IYH:if (strcmp(zeexpression,"IYH")==0) return 1; else return 0; + default:break; + } + return 0; +} + +int StringIsMem(char *w) +{ + #undef FUNC + #define FUNC "StringIsMem" + + int p=1,idx=1; + + if (w[0]=='(') { + while (w[idx]) { + switch (w[idx]) { + case '\\':if (w[idx+1]) idx++; + break; + case '\'':if (w[idx+1] && w[idx+1]!='\\') idx++; + break; + case '(':p++;break; + case ')':p--; + if (!p && w[idx+1]) return 0; + break; + default:break; + } + idx++; + } + if (w[idx-1]!=')') return 0; + } else { + return 0; + } + return 1; + +} +int StringIsQuote(char *w) +{ + #undef FUNC + #define FUNC "StringIsQuote" + + int i,tquote,lens; + + if (w[0]=='\'' || w[0]=='"') { + tquote=w[0]; + lens=strlen(w); + + /* est-ce bien une chaine et uniquement une chaine? */ + i=1; + while (w[i] && w[i]!=tquote) { + if (w[i]=='\\') i++; + i++; + } + if (i==lens-1) { + return tquote; + } + } + return 0; +} +char *StringLooksLikeDicoRecurse(struct s_crcdico_tree *lt, int *score, char *str) +{ + #undef FUNC + #define FUNC "StringLooksLikeDicoRecurse" + + char *retstr=NULL,*tmpstr; + int i,curs; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + tmpstr=StringLooksLikeDicoRecurse(lt->radix[i],score,str); + if (tmpstr!=NULL) retstr=tmpstr; + } + } + if (lt->mdico) { + for (i=0;i<lt->ndico;i++) { + if (strlen(lt->dico[i].name)>4) { + curs=_internal_LevenshteinDistance(str,lt->dico[i].name); + if (curs<*score) { + *score=curs; + retstr=lt->dico[i].name; + } + } + } + } + return retstr; +} +char *StringLooksLikeDico(struct s_assenv *ae, int *score, char *str) +{ + #undef FUNC + #define FUNC "StringLooksLikeDico" + + char *retstr=NULL,*tmpstr; + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + tmpstr=StringLooksLikeDicoRecurse(ae->dicotree.radix[i],score,str); + if (tmpstr!=NULL) retstr=tmpstr; + } + } + return retstr; +} +char *StringLooksLikeMacro(struct s_assenv *ae, char *str, int *retscore) +{ + #undef FUNC + #define FUNC "StringLooksLikeMacro" + + char *ret=NULL; + int i,curs,score=3; + /* search in macros */ + for (i=0;i<ae->imacro;i++) { + curs=_internal_LevenshteinDistance(ae->macro[i].mnemo,str); + if (curs<score) { + score=curs; + ret=ae->macro[i].mnemo; + } + } + if (retscore) *retscore=score; + return ret; +} + +char *StringLooksLike(struct s_assenv *ae, char *str) +{ + #undef FUNC + #define FUNC "StringLooksLike" + + char *ret=NULL,*tmpret; + int i,curs,score=4; + + /* search in variables */ + ret=StringLooksLikeDico(ae,&score,str); + + /* search in labels */ + for (i=0;i<ae->il;i++) { + if (!ae->label[i].name && strlen(ae->wl[ae->label[i].iw].w)>4) { + curs=_internal_LevenshteinDistance(ae->wl[ae->label[i].iw].w,str); + if (curs<score) { + score=curs; + ret=ae->wl[ae->label[i].iw].w; + } + } + } + + /* search in alias */ + for (i=0;i<ae->ialias;i++) { + if (strlen(ae->alias[i].alias)>4) { + curs=_internal_LevenshteinDistance(ae->alias[i].alias,str); + if (curs<score) { + score=curs; + ret=ae->alias[i].alias; + } + } + } + + tmpret=StringLooksLikeMacro(ae,str,&curs); + if (curs<score) { + score=curs; + ret=tmpret; + } + return ret; +} + +int RoundComputeExpression(struct s_assenv *ae,char *expr, int ptr, int didx, int expression_expected); +int RoundComputeExpressionCore(struct s_assenv *ae,char *zeexpression,int ptr,int didx); +double ComputeExpressionCore(struct s_assenv *ae,char *original_zeexpression,int ptr, int didx); +char *GetExpFile(struct s_assenv *ae,int didx); +void __STOP(struct s_assenv *ae); + + +void MakeError(struct s_assenv *ae, char *filename, int line, char *format, ...) +{ + #undef FUNC + #define FUNC "MakeError" + + va_list argptr; + + MaxError(ae); + if (ae->flux) { + /* in embedded Rasm all errors are stored in a debug struct */ + struct s_debug_error curerror; + char toosmalltotakeitall[2]={0}; + int myalloc; + char *errstr; + + va_start(argptr,format); + myalloc=vsnprintf(toosmalltotakeitall,1,format,argptr); + va_end(argptr); + + #if defined(_MSC_VER) && _MSC_VER < 1900 + /* visual studio before 2015 does not fully support C99 */ + if (myalloc<1 && strlen(format)) { + va_start(argptr,format); + myalloc=_vscprintf(format,argptr); + va_end(argptr); + } + #endif + if (myalloc<1) { + /* do not crash */ + return; + } + + va_start(argptr,format); + errstr=MemMalloc(myalloc+1); + vsnprintf(errstr,myalloc,format,argptr); + curerror.msg=errstr; + curerror.lenmsg=myalloc; + curerror.line=line; + if (filename) curerror.filename=TxtStrDupLen(filename,&curerror.lenfilename); else curerror.filename=TxtStrDupLen("<internal>",&curerror.lenfilename); + ObjectArrayAddDynamicValueConcat((void **)&ae->debug.error,&ae->debug.nberror,&ae->debug.maxerror,&curerror,sizeof(struct s_debug_error)); + va_end(argptr); + } else { + fprintf(stdout,KERROR); + va_start(argptr,format); + if (filename && line) { + printf("[%s:%d] ",filename,line); + } else if (filename) { + printf("[%s] ",filename); + } + vfprintf(stdout,format,argptr); + va_end(argptr); + fprintf(stdout,KNORMAL); + } +} + + +/* convert v double value to Amstrad REAL */ +unsigned char *__internal_MakeAmsdosREAL(struct s_assenv *ae, double v, int iexpression) +{ + #undef FUNC + #define FUNC "__internal_MakeAmsdosREAL" + + static unsigned char rc[5]; + + double tmpval; + int j,ib,ibb,exp=0; + unsigned int deci; + int fracmax=0; + double frac; + int mesbits[32]; + int ibit=0; + unsigned int mask; + + memset(rc,0,sizeof(rc)); + + deci=fabs(floor(v)); + frac=fabs(v)-deci; + + if (deci) { + mask=0x80000000; + while (!(deci & mask)) mask=mask/2; + while (mask) { + mesbits[ibit]=!!(deci & mask); +#if TRACE_MAKEAMSDOSREAL +printf("%d",mesbits[ibit]); +#endif + ibit++; + mask=mask/2; + } +#if TRACE_MAKEAMSDOSREAL +printf("\nexposant positif: %d\n",ibit); +#endif + exp=ibit; +#if TRACE_MAKEAMSDOSREAL +printf("."); +#endif + while (ibit<32 && frac!=0) { + frac=frac*2; + if (frac>=1.0) { + mesbits[ibit++]=1; +#if TRACE_MAKEAMSDOSREAL +printf("1"); +#endif + frac-=1.0; + } else { + mesbits[ibit++]=0; +#if TRACE_MAKEAMSDOSREAL +printf("0"); +#endif + } + fracmax++; + } + } else { +#if TRACE_MAKEAMSDOSREAL +printf("\nexposant negatif a definir:\n"); +printf("x."); +#endif + + /* handling zero */ + if (frac==0.0) { + exp=0; + ibit=0; + } else { + /* looking for first significant bit */ + while (1) { + frac=frac*2; + if (frac>=1.0) { + mesbits[ibit++]=1; +#if TRACE_MAKEAMSDOSREAL +printf("1"); +#endif + frac-=1.0; + break; /* first significant bit found, now looking for limit */ + } else { +#if TRACE_MAKEAMSDOSREAL +printf("o"); +#endif + } + fracmax++; + exp--; + } + while (ibit<32 && frac!=0) { + frac=frac*2; + if (frac>=1.0) { + mesbits[ibit++]=1; +#if TRACE_MAKEAMSDOSREAL +printf("1"); +#endif + frac-=1.0; + } else { + mesbits[ibit++]=0; +#if TRACE_MAKEAMSDOSREAL +printf("0"); +#endif + } + fracmax++; + } + } + } + +#if TRACE_MAKEAMSDOSREAL +printf("\n%d bits utilises en mantisse\n",ibit); +#endif + /* pack bits */ + ib=3;ibb=0x80; + for (j=0;j<ibit;j++) { + if (mesbits[j]) rc[ib]|=ibb; + ibb/=2; + if (ibb==0) { + ibb=0x80; + ib--; + } + } + /* exponent */ + exp+=128; + if (exp<0 || exp>255) { + if (iexpression) MakeError(ae,GetExpFile(ae,iexpression),ae->wl[ae->expression[iexpression].iw].l,"Exponent overflow\n"); + else MakeError(ae,GetExpFile(ae,0),ae->wl[ae->idx].l,"Exponent overflow\n"); + exp=128; + } + rc[4]=exp; + + /* REAL sign */ + if (v>=0) { + rc[3]&=0x7F; + } else { + rc[3]|=0x80; + } + +#if TRACE_MAKEAMSDOSREAL + for (j=0;j<5;j++) printf("%02X ",rc[j]); + printf("\n"); +#endif + + return rc; +} + + + + +struct s_label *SearchLabel(struct s_assenv *ae, char *label, int crc); +char *GetExpFile(struct s_assenv *ae,int didx){ + #undef FUNC + #define FUNC "GetExpFile" + + if (ae->label_filename) { + return ae->label_filename; + } + if (didx<0) { + return ae->filename[ae->wl[-didx].ifile]; + } else if (!didx) { + return ae->filename[ae->wl[ae->idx].ifile]; + } else if (ae->expression && didx<ae->ie) { + return ae->filename[ae->wl[ae->expression[didx].iw].ifile]; + } else { + //return ae->filename[ae->wl[ae->idx].ifile]; + return 0; + } +} + +int GetExpLine(struct s_assenv *ae,int didx){ + #undef FUNC + #define FUNC "GetExpLine" + + if (ae->label_line) return ae->label_line; + + if (didx<0) { + return ae->wl[-didx].l; + } else if (!didx) { + return ae->wl[ae->idx].l; + } else if (didx<ae->ie) { + return ae->wl[ae->expression[didx].iw].l; + } else return 0; +} + +char *GetCurrentFile(struct s_assenv *ae) +{ + return GetExpFile(ae,0); +} + + +/******************************************************************************************* + M E M O R Y C L E A N U P +*******************************************************************************************/ +void FreeLabelTree(struct s_assenv *ae); +void FreeDicoTree(struct s_assenv *ae); +void FreeUsedTree(struct s_assenv *ae); +void ExpressionFastTranslate(struct s_assenv *ae, char **ptr_expr, int fullreplace); +char *TradExpression(char *zexp); + + +void _internal_RasmFreeInfoStruct(struct s_rasm_info *debug) +{ + #undef FUNC + #define FUNC "RasmFreeInfoStruct" + + int i; + if (debug->maxerror) { + for (i=0;i<debug->nberror;i++) { + MemFree(debug->error[i].filename); + MemFree(debug->error[i].msg); + } + MemFree(debug->error); + } + if (debug->maxsymbol) { + for (i=0;i<debug->nbsymbol;i++) { + MemFree(debug->symbol[i].name); + } + MemFree(debug->symbol); + } +} + +void RasmFreeInfoStruct(struct s_rasm_info *debug) +{ + _internal_RasmFreeInfoStruct(debug); + MemFree(debug); +} + +void FreeAssenv(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeAssenv" + int i,j; + +#ifndef RDD + /* let the system free the memory in command line except when debug/dev */ + if (!ae->flux) return; +#endif + /*** debug info ***/ + if (!ae->retdebug) { + _internal_RasmFreeInfoStruct(&ae->debug); + } else { + /* symbols */ + struct s_debug_symbol debug_symbol={0}; + + for (i=0;i<ae->il;i++) { + /* on exporte tout */ + if (!ae->label[i].name) { + /* les labels entiers */ + debug_symbol.name=TxtStrDup(ae->wl[ae->label[i].iw].w); + debug_symbol.v=ae->label[i].ptr; + ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); + } else { + /* les labels locaux et générés */ + debug_symbol.name=TxtStrDup(ae->label[i].name); + debug_symbol.v=ae->label[i].ptr; + ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); + } + } + for (i=0;i<ae->ialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + debug_symbol.name=TxtStrDup(ae->alias[i].alias); + debug_symbol.v=RoundComputeExpression(ae,ae->alias[i].translation,0,0,0); + ObjectArrayAddDynamicValueConcat((void**)&ae->debug.symbol,&ae->debug.nbsymbol,&ae->debug.maxsymbol,&debug_symbol,sizeof(struct s_debug_symbol)); + } + } + + /* export struct */ + *ae->retdebug=MemMalloc(sizeof(struct s_rasm_info)); + memcpy(*ae->retdebug,&ae->debug,sizeof(struct s_rasm_info)); + } + /*** end debug ***/ + + for (i=0;i<ae->nbbank;i++) { + MemFree(ae->mem[i]); + } + MemFree(ae->mem); + + /* expression core buffer free */ + ComputeExpressionCore(NULL,NULL,0,0); + ExpressionFastTranslate(NULL,NULL,0); + /* free labels, expression, orgzone, repeat, ... */ + if (ae->mo) MemFree(ae->orgzone); + if (ae->me) { + for (i=0;i<ae->ie;i++) if (ae->expression[i].reference) MemFree(ae->expression[i].reference); + MemFree(ae->expression); + } + if (ae->mh) { + for (i=0;i<ae->ih;i++) { + MemFree(ae->hexbin[i].data); + MemFree(ae->hexbin[i].filename); + } + MemFree(ae->hexbin); + } + for (i=0;i<ae->il;i++) { + if (ae->label[i].name && ae->label[i].iw==-1) MemFree(ae->label[i].name); + } + /* structures */ + for (i=0;i<ae->irasmstructalias;i++) { + MemFree(ae->rasmstructalias[i].name); + } + if (ae->mrasmstructalias) MemFree(ae->rasmstructalias); + + for (i=0;i<ae->irasmstruct;i++) { + for (j=0;j<ae->rasmstruct[i].irasmstructfield;j++) { + MemFree(ae->rasmstruct[i].rasmstructfield[j].fullname); + MemFree(ae->rasmstruct[i].rasmstructfield[j].name); + } + if (ae->rasmstruct[i].mrasmstructfield) MemFree(ae->rasmstruct[i].rasmstructfield); + MemFree(ae->rasmstruct[i].name); + } + if (ae->mrasmstruct) MemFree(ae->rasmstruct); + + /* other */ + if (ae->maxbreakpoint) MemFree(ae->breakpoint); + if (ae->ml) MemFree(ae->label); + if (ae->mr) MemFree(ae->repeat); + if (ae->mi) MemFree(ae->ifthen); + if (ae->msw) MemFree(ae->switchcase); + if (ae->mw) MemFree(ae->whilewend); + if (ae->modulen || ae->module) { + MemFree(ae->module); + } + /* deprecated + for (i=0;i<ae->idic;i++) { + MemFree(ae->dico[i].name); + } + if (ae->mdic) MemFree(ae->dico); + */ + if (ae->mlz) MemFree(ae->lzsection); + + for (i=0;i<ae->ifile;i++) { + MemFree(ae->filename[i]); + } + MemFree(ae->filename); + + for (i=0;i<ae->imacro;i++) { + if (ae->macro[i].maxword) MemFree(ae->macro[i].wc); + for (j=0;j<ae->macro[i].nbparam;j++) MemFree(ae->macro[i].param[j]); + if (ae->macro[i].nbparam) MemFree(ae->macro[i].param); + } + + + if (ae->mmacro) MemFree(ae->macro); + + for (i=0;i<ae->ialias;i++) { + MemFree(ae->alias[i].alias); + MemFree(ae->alias[i].translation); + } + if (ae->malias) MemFree(ae->alias); + + for (i=0;ae->wl[i].t!=2;i++) { + MemFree(ae->wl[i].w); + } + MemFree(ae->wl); + + if (ae->ctx1.varbuffer) { + MemFree(ae->ctx1.varbuffer); + } + if (ae->ctx1.maxtokenstack) { + MemFree(ae->ctx1.tokenstack); + } + if (ae->ctx1.maxoperatorstack) { + MemFree(ae->ctx1.operatorstack); + } + if (ae->ctx2.varbuffer) { + MemFree(ae->ctx2.varbuffer); + } + if (ae->ctx2.maxtokenstack) { + MemFree(ae->ctx2.tokenstack); + } + if (ae->ctx2.maxoperatorstack) { + MemFree(ae->ctx2.operatorstack); + } + + for (i=0;i<ae->iticker;i++) { + MemFree(ae->ticker[i].varname); + } + if (ae->mticker) MemFree(ae->ticker); + + MemFree(ae->outputfilename); + FreeLabelTree(ae); + FreeDicoTree(ae); + FreeUsedTree(ae); + if (ae->mmacropos) MemFree(ae->macropos); + TradExpression(NULL); + MemFree(ae); +} + + + +void MaxError(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "MaxError" + + char **source_lines=NULL; + int idx,crc,zeline; + char c; + + /* extended error is useful with generated code we do not want to edit */ + if (ae->extended_error && ae->wl) { + /* super dupper slow but anyway, there is an error... */ + if (ae->wl[ae->idx].l) { + source_lines=FileReadLinesRAW(GetCurrentFile(ae)); + zeline=0; + while (zeline<ae->wl[ae->idx].l-1 && source_lines[zeline]) zeline++; + if (zeline==ae->wl[ae->idx].l-1 && source_lines[zeline]) { + rasm_printf(ae,KAYGREEN"-> %s",source_lines[zeline]); + } else { + rasm_printf(ae,KERROR"cannot read line %d of file [%s]\n",ae->wl[ae->idx].l,GetCurrentFile(ae)); + } + FreeArrayDynamicValue(&source_lines); + } + } + + ae->nberr++; + if (ae->nberr==ae->maxerr) { + rasm_printf(ae,KERROR"Too many errors!\n"); + FreeAssenv(ae); + exit(ae->nberr); + } +} + +void (*___output)(struct s_assenv *ae, unsigned char v); + +void ___internal_output_disabled(struct s_assenv *ae,unsigned char v) +{ + #undef FUNC + #define FUNC "fake ___output" +} +void ___internal_output(struct s_assenv *ae,unsigned char v) +{ + #undef FUNC + #define FUNC "___output" + + if (ae->outputadr<ae->maxptr) { + ae->mem[ae->activebank][ae->outputadr++]=v; + ae->codeadr++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); + ae->stop=1; + ___output=___internal_output_disabled; + } +} +void ___internal_output_nocode(struct s_assenv *ae,unsigned char v) +{ + #undef FUNC + #define FUNC "___output (nocode)" + + if (ae->outputadr<ae->maxptr) { + /* struct definition always in NOCODE */ + if (ae->getstruct) { + int irs,irsf; + irs=ae->irasmstruct-1; + irsf=ae->rasmstruct[irs].irasmstructfield-1; + + /* ajouter les data du flux au champ de la structure */ + ObjectArrayAddDynamicValueConcat((void**)&ae->rasmstruct[irs].rasmstructfield[irsf].data, + &ae->rasmstruct[irs].rasmstructfield[irsf].idata, + &ae->rasmstruct[irs].rasmstructfield[irsf].mdata, + &v,sizeof(unsigned char)); + } + + ae->outputadr++; + ae->codeadr++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); + ae->stop=1; + ___output=___internal_output_disabled; + } +} + + +void ___output_set_limit(struct s_assenv *ae,int zelimit) +{ + #undef FUNC + #define FUNC "___output_set_limit" + + int limit=65535; + + if (zelimit<=limit) { + /* apply limit */ + limit=zelimit; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"limit exceed hardware limitation!"); + ae->stop=1; + } + if (ae->outputadr>=0 && ae->outputadr>limit) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"limit too high for current output!"); + ae->stop=1; + } + ae->maxptr=limit; +} + +unsigned char *MakeAMSDOSHeader(int run, int minmem, int maxmem, char *amsdos_name) { + #undef FUNC + #define FUNC "MakeAMSDOSHeader" + + static unsigned char AmsdosHeader[128]; + int checksum,i=0; + /*** cpcwiki + Byte 00: User number + Byte 01 to 08: filename + Byte 09 bis 11: Extension + Byte 18: type-byte + Byte 21 and 22: loading address + Byte 24 and 25: file length + Byte 26 and 27: execution address for machine code programs + Byte 64 and 65: (file length) + Byte 67 and 68: checksum for byte 00 to byte 66 + To calculate the checksum, just add byte 00 to byte 66 to each other. + */ + memset(AmsdosHeader,0,sizeof(AmsdosHeader)); + AmsdosHeader[0]=0; + memcpy(AmsdosHeader+1,amsdos_name,11); + + AmsdosHeader[18]=2; /* 0 basic 1 basic protege 2 binaire */ + AmsdosHeader[19]=(maxmem-minmem)&0xFF; + AmsdosHeader[20]=(maxmem-minmem)>>8; + AmsdosHeader[21]=minmem&0xFF; + AmsdosHeader[22]=minmem>>8; + AmsdosHeader[24]=AmsdosHeader[19]; + AmsdosHeader[25]=AmsdosHeader[20]; + AmsdosHeader[26]=run&0xFF; + AmsdosHeader[27]=run>>8; + AmsdosHeader[64]=AmsdosHeader[19]; + AmsdosHeader[65]=AmsdosHeader[20]; + AmsdosHeader[66]=0; + + for (i=checksum=0;i<=66;i++) { + checksum+=AmsdosHeader[i]; + } + AmsdosHeader[67]=checksum&0xFF; + AmsdosHeader[68]=checksum>>8; + + /* garbage / shadow values from sector buffer? */ + memcpy(AmsdosHeader+0x47,amsdos_name,8); + AmsdosHeader[0x4F]=0x24; + AmsdosHeader[0x50]=0x24; + AmsdosHeader[0x51]=0x24; + AmsdosHeader[0x52]=0xFF; + AmsdosHeader[0x54]=0xFF; + AmsdosHeader[0x57]=0x02; + AmsdosHeader[0x5A]=AmsdosHeader[21]; + AmsdosHeader[0x5B]=AmsdosHeader[22]; + AmsdosHeader[0x5D]=AmsdosHeader[24]; + AmsdosHeader[0x5E]=AmsdosHeader[25]; + + sprintf((char *)AmsdosHeader+0x47+17," generated by %s ",RASM_SNAP_VERSION); + + return AmsdosHeader; +} + +unsigned char *MakeHobetaHeader(int minmem, int maxmem, char *trdos_name) { + #undef FUNC + #define FUNC "MakeHobetaHeader" + + static unsigned char HobetaHeader[17]; + int i,checksum=0; + /*** http://rk.nvg.ntnu.no/sinclair/faq/fileform.html#HOBETA + 0x00 FileName 0x08 TR-DOS file name + 0x08 FileType 0x01 TR-DOS file type + 0x09 StartAdr 0x02 start address of file + 0x0A FlLength 0x02 length of file (in bytes) -> /!\ wrong offset!!! + 0x0C FileSize 0x02 size of file (in sectors) + 0x0E HdrCRC16 0x02 Control checksum of the 15 byte + header (not sector data!) + */ + memset(HobetaHeader,0,sizeof(HobetaHeader)); + + strncpy(HobetaHeader,trdos_name,8); + HobetaHeader[8]='C'; + HobetaHeader[0x9]=(maxmem-minmem)&0xFF; + HobetaHeader[0xA]=(maxmem-minmem)>>8; + + HobetaHeader[0xB]=(maxmem-minmem)&0xFF; + HobetaHeader[0xC]=(maxmem-minmem)>>8; + + HobetaHeader[0xD]=((maxmem-minmem)+255)>>8; + HobetaHeader[0xE]=0; + + for (i=0;i<0xF;i++) checksum+=HobetaHeader[i]*257+i; + + HobetaHeader[0xF]=checksum&0xFF; + HobetaHeader[0x10]=(checksum>>8)&0xFF; + + return HobetaHeader; +} + + +int cmpAmsdosentry(const void * a, const void * b) +{ + return memcmp(a,b,32); +} + +int cmpmacros(const void * a, const void * b) +{ + struct s_macro *sa,*sb; + sa=(struct s_macro *)a; + sb=(struct s_macro *)b; + if (sa->crc<sb->crc) return -1; else return 1; +} +int SearchAlias(struct s_assenv *ae, int crc, char *zemot) +{ + int dw,dm,du,i; +//printf("SearchAlias [%s] ",zemot); + /* inutile de tourner autour du pot pour un si petit nombre */ + if (ae->ialias<5) { + for (i=0;i<ae->ialias;i++) { + if (ae->alias[i].crc==crc && strcmp(ae->alias[i].alias,zemot)==0) { + ae->alias[i].used=1; +//printf("found\n"); + return i; + } + } +//printf("not found\n"); + return -1; + } + + dw=0; + du=ae->ialias-1; + while (dw<=du) { + dm=(dw+du)/2; + if (ae->alias[dm].crc==crc) { + /* chercher le premier de la liste */ + while (dm>0 && ae->alias[dm-1].crc==crc) dm--; + /* controle sur le texte entier */ + while (ae->alias[dm].crc==crc && strcmp(ae->alias[dm].alias,zemot)) dm++; + if (ae->alias[dm].crc==crc && strcmp(ae->alias[dm].alias,zemot)==0) { + ae->alias[dm].used=1; +//printf("found\n"); + return dm; + } else return -1; + } else if (ae->alias[dm].crc>crc) { + du=dm-1; + } else if (ae->alias[dm].crc<crc) { + dw=dm+1; + } + } +//printf("not found\n"); + return -1; +} +int SearchMacro(struct s_assenv *ae, int crc, char *zemot) +{ + int dw,dm,du,i; + + /* inutile de tourner autour du pot pour un si petit nombre */ + if (ae->imacro<5) { + for (i=0;i<ae->imacro;i++) { + if (ae->macro[i].crc==crc && strcmp(ae->macro[i].mnemo,zemot)==0) { + return i; + } + } + return -1; + } + + dw=0; + du=ae->imacro-1; + while (dw<=du) { + dm=(dw+du)/2; + if (ae->macro[dm].crc==crc) { + /* chercher le premier de la liste */ + while (dm>0 && ae->macro[dm-1].crc==crc) dm--; + /* controle sur le texte entier */ + while (ae->macro[dm].crc==crc && strcmp(ae->macro[dm].mnemo,zemot)) dm++; + if (ae->macro[dm].crc==crc && strcmp(ae->macro[dm].mnemo,zemot)==0) return dm; else return -1; + } else if (ae->macro[dm].crc>crc) { + du=dm-1; + } else if (ae->macro[dm].crc<crc) { + dw=dm+1; + } + } + return -1; +} + +void CheckAndSortAliases(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "CheckAndSortAliases" + + struct s_alias tmpalias; + int i,dw,dm,du,crc; + for (i=0;i<ae->ialias-1;i++) { + /* is there previous aliases in the new alias? */ + if (strstr(ae->alias[ae->ialias-1].translation,ae->alias[i].alias)) { + /* there is a match, apply alias translation */ + ExpressionFastTranslate(ae,&ae->alias[ae->ialias-1].translation,2); + /* need to compute again len */ + ae->alias[ae->ialias-1].len=strlen(ae->alias[ae->ialias-1].translation); + break; + } + } + + /* cas particuliers pour insertion en début ou fin de liste */ + if (ae->ialias-1) { + if (ae->alias[ae->ialias-1].crc>ae->alias[ae->ialias-2].crc) { + /* pas de tri il est déjà au bon endroit */ + } else if (ae->alias[ae->ialias-1].crc<ae->alias[0].crc) { + /* insertion tout en bas de liste */ + tmpalias=ae->alias[ae->ialias-1]; + MemMove(&ae->alias[1],&ae->alias[0],sizeof(struct s_alias)*(ae->ialias-1)); + ae->alias[0]=tmpalias; + } else { + /* on cherche ou inserer */ + crc=ae->alias[ae->ialias-1].crc; + dw=0; + du=ae->ialias-1; + while (dw<=du) { + dm=(dw+du)/2; + if (ae->alias[dm].crc==crc) { + break; + } else if (ae->alias[dm].crc>crc) { + du=dm-1; + } else if (ae->alias[dm].crc<crc) { + dw=dm+1; + } + } + /* ajustement */ + if (ae->alias[dm].crc<crc) dm++; + /* insertion */ + tmpalias=ae->alias[ae->ialias-1]; + MemMove(&ae->alias[dm+1],&ae->alias[dm],sizeof(struct s_alias)*(ae->ialias-1-dm)); + ae->alias[dm]=tmpalias; + } + } else { + /* one alias need no sort */ + } +} + +void InsertDicoToTree(struct s_assenv *ae, struct s_expr_dico *dico) +{ + #undef FUNC + #define FUNC "InsertDicoToTree" + + struct s_crcdico_tree *curdicotree; + int radix,dek=32; + + curdicotree=&ae->dicotree; + while (dek) { + dek=dek-8; + radix=(dico->crc>>dek)&0xFF; + if (curdicotree->radix[radix]) { + curdicotree=curdicotree->radix[radix]; + } else { + curdicotree->radix[radix]=MemMalloc(sizeof(struct s_crcdico_tree)); + curdicotree=curdicotree->radix[radix]; + memset(curdicotree,0,sizeof(struct s_crcdico_tree)); + } + } + ObjectArrayAddDynamicValueConcat((void**)&curdicotree->dico,&curdicotree->ndico,&curdicotree->mdico,dico,sizeof(struct s_expr_dico)); +} + +unsigned char *SnapshotDicoInsert(char *symbol_name, int ptr, int *retidx) +{ + static unsigned char *subchunk=NULL; + static int subchunksize=0; + static int idx=0; + int symbol_len; + + if (retidx) { + if (symbol_name && strcmp(symbol_name,"FREE")==0) { + subchunksize=0; + idx=0; + MemFree(subchunk); + subchunk=NULL; + } + *retidx=idx; + return subchunk; + } + + if (idx+65536>subchunksize) { + subchunksize=subchunksize+65536; + subchunk=MemRealloc(subchunk,subchunksize); + } + + symbol_len=strlen(symbol_name); + if (symbol_len>255) symbol_len=255; + subchunk[idx++]=symbol_len; + memcpy(subchunk+idx,symbol_name,symbol_len); + idx+=symbol_len; + memset(subchunk+idx,0,6); + idx+=6; + subchunk[idx++]=(ptr&0xFF00)/256; + subchunk[idx++]=ptr&0xFF; + return NULL; +} + +void SnapshotDicoTreeRecurse(struct s_crcdico_tree *lt) +{ + #undef FUNC + #define FUNC "SnapshottDicoTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + SnapshotDicoTreeRecurse(lt->radix[i]); + } + } + if (lt->mdico) { + for (i=0;i<lt->ndico;i++) { + if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM")) { + SnapshotDicoInsert(lt->dico[i].name,(int)floor(lt->dico[i].v+0.5),NULL); + } + } + } +} +unsigned char *SnapshotDicoTree(struct s_assenv *ae, int *retidx) +{ + #undef FUNC + #define FUNC "SnapshotDicoTree" + + unsigned char *sc; + int idx; + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + SnapshotDicoTreeRecurse(ae->dicotree.radix[i]); + } + } + + sc=SnapshotDicoInsert(NULL,0,&idx); + *retidx=idx; + return sc; +} + +void WarnLabelTreeRecurse(struct s_assenv *ae, struct s_crclabel_tree *lt) +{ + #undef FUNC + #define FUNC "WarnLabelTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + WarnLabelTreeRecurse(ae,lt->radix[i]); + } + } + for (i=0;i<lt->nlabel;i++) { + if (!lt->label[i].used) { + if (!lt->label[i].name) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: label %s declared but not used\n",ae->filename[lt->label[i].fileidx],lt->label[i].fileline,ae->wl[lt->label[i].iw].w); + } else { + rasm_printf(ae,KWARNING"[%s:%d] Warning: label %s declared but not used\n",ae->filename[lt->label[i].fileidx],lt->label[i].fileline,lt->label[i].name); + } + } + } +} +void WarnLabelTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "WarnLabelTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->labeltree.radix[i]) { + WarnLabelTreeRecurse(ae,ae->labeltree.radix[i]); + } + } +} +void WarnDicoTreeRecurse(struct s_assenv *ae, struct s_crcdico_tree *lt) +{ + #undef FUNC + #define FUNC "WarnDicoTreeRecurse" + + char symbol_line[1024]; + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + WarnDicoTreeRecurse(ae,lt->radix[i]); + } + } + for (i=0;i<lt->ndico;i++) { + if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM") && lt->dico[i].autorise_export) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: variable %s declared but not used\n",ae->filename[ae->wl[lt->dico[i].iw].ifile],ae->wl[lt->dico[i].iw].l,lt->dico[i].name); + } + } +} +void WarnDicoTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "ExportDicoTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + WarnDicoTreeRecurse(ae,ae->dicotree.radix[i]); + } + } +} +void ExportDicoTreeRecurse(struct s_crcdico_tree *lt, char *zefile, char *zeformat) +{ + #undef FUNC + #define FUNC "ExportDicoTreeRecurse" + + char symbol_line[1024]; + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + ExportDicoTreeRecurse(lt->radix[i],zefile,zeformat); + } + } + if (lt->mdico) { + for (i=0;i<lt->ndico;i++) { + if (strcmp(lt->dico[i].name,"IX") && strcmp(lt->dico[i].name,"IY") && strcmp(lt->dico[i].name,"PI") && strcmp(lt->dico[i].name,"ASSEMBLER_RASM") && lt->dico[i].autorise_export) { + snprintf(symbol_line,sizeof(symbol_line)-1,zeformat,lt->dico[i].name,(int)floor(lt->dico[i].v+0.5)); + symbol_line[sizeof(symbol_line)-1]=0xD; + FileWriteLine(zefile,symbol_line); + } + } + } +} +void ExportDicoTree(struct s_assenv *ae, char *zefile, char *zeformat) +{ + #undef FUNC + #define FUNC "ExportDicoTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + ExportDicoTreeRecurse(ae->dicotree.radix[i],zefile,zeformat); + } + } +} +void FreeDicoTreeRecurse(struct s_crcdico_tree *lt) +{ + #undef FUNC + #define FUNC "FreeDicoTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeDicoTreeRecurse(lt->radix[i]); + } + } + if (lt->mdico) { + for (i=0;i<lt->ndico;i++) { + MemFree(lt->dico[i].name); + } + MemFree(lt->dico); + } + MemFree(lt); +} +void FreeDicoTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeDicoTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->dicotree.radix[i]) { + FreeDicoTreeRecurse(ae->dicotree.radix[i]); + } + } + if (ae->dicotree.mdico) { + for (i=0;i<ae->dicotree.ndico;i++) MemFree(ae->dicotree.dico[i].name); + MemFree(ae->dicotree.dico); + } +} +struct s_expr_dico *SearchDico(struct s_assenv *ae, char *dico, int crc) +{ + #undef FUNC + #define FUNC "SearchDico" + + struct s_crcdico_tree *curdicotree; + struct s_expr_dico *retdico=NULL; + int i,radix,dek=32; + + curdicotree=&ae->dicotree; + + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curdicotree->radix[radix]) { + curdicotree=curdicotree->radix[radix]; + } else { + /* radix not found, dico is not in index */ + return NULL; + } + } + for (i=0;i<curdicotree->ndico;i++) { + if (strcmp(curdicotree->dico[i].name,dico)==0) { + curdicotree->dico[i].used=1; + return &curdicotree->dico[i]; + } + } + return NULL; +} +int DelDico(struct s_assenv *ae, char *dico, int crc) +{ + #undef FUNC + #define FUNC "DelDico" + + struct s_crcdico_tree *curdicotree; + struct s_expr_dico *retdico=NULL; + int i,radix,dek=32; + + curdicotree=&ae->dicotree; + + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curdicotree->radix[radix]) { + curdicotree=curdicotree->radix[radix]; + } else { + /* radix not found, dico is not in index */ + return 0; + } + } + for (i=0;i<curdicotree->ndico;i++) { + if (strcmp(curdicotree->dico[i].name,dico)==0) { + /* must free memory */ + MemFree(curdicotree->dico[i].name); + if (i<curdicotree->ndico-1) { + MemMove(&curdicotree->dico[i],&curdicotree->dico[i+1],(curdicotree->ndico-i-1)*sizeof(struct s_expr_dico)); + } + curdicotree->ndico--; + return 1; + } + } + return 0; +} + + +void InsertUsedToTree(struct s_assenv *ae, char *used, int crc) +{ + #undef FUNC + #define FUNC "InsertUsedToTree" + + struct s_crcused_tree *curusedtree; + int radix,dek=32,i; + + curusedtree=&ae->usedtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curusedtree->radix[radix]) { + curusedtree=curusedtree->radix[radix]; + } else { + curusedtree->radix[radix]=MemMalloc(sizeof(struct s_crcused_tree)); + curusedtree=curusedtree->radix[radix]; + memset(curusedtree,0,sizeof(struct s_crcused_tree)); + } + } + for (i=0;i<curusedtree->nused;i++) if (strcmp(used,curusedtree->used[i])==0) break; + /* no double */ + if (i==curusedtree->nused) { + FieldArrayAddDynamicValueConcat(&curusedtree->used,&curusedtree->nused,&curusedtree->mused,used); + } +} + +void FreeUsedTreeRecurse(struct s_crcused_tree *lt) +{ + #undef FUNC + #define FUNC "FreeUsedTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeUsedTreeRecurse(lt->radix[i]); + } + } + if (lt->mused) { + for (i=0;i<lt->nused;i++) MemFree(lt->used[i]); + MemFree(lt->used); + } + MemFree(lt); +} +void FreeUsedTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeUsedTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->usedtree.radix[i]) { + FreeUsedTreeRecurse(ae->usedtree.radix[i]); + } + } +} +int SearchUsed(struct s_assenv *ae, char *used, int crc) +{ + #undef FUNC + #define FUNC "SearchUsed" + + struct s_crcused_tree *curusedtree; + int i,radix,dek=32; + + curusedtree=&ae->usedtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curusedtree->radix[radix]) { + curusedtree=curusedtree->radix[radix]; + } else { + /* radix not found, used is not in index */ + return 0; + } + } + for (i=0;i<curusedtree->nused;i++) { + if (strcmp(curusedtree->used[i],used)==0) { + return 1; + } + } + return 0; +} + + + +void InsertTextToTree(struct s_assenv *ae, char *text, char *replace, int crc) +{ + #undef FUNC + #define FUNC "InsertTextToTree" + + struct s_crcstring_tree *curstringtree; + int radix,dek=32,i; + + curstringtree=&ae->stringtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curstringtree->radix[radix]) { + curstringtree=curstringtree->radix[radix]; + } else { + curstringtree->radix[radix]=MemMalloc(sizeof(struct s_crcused_tree)); + curstringtree=curstringtree->radix[radix]; + memset(curstringtree,0,sizeof(struct s_crcused_tree)); + } + } + for (i=0;i<curstringtree->ntext;i++) if (strcmp(text,curstringtree->text[i])==0) break; + /* no double */ + if (i==curstringtree->ntext) { + text=TxtStrDup(text); + replace=TxtStrDup(replace); + FieldArrayAddDynamicValueConcat(&curstringtree->text,&curstringtree->ntext,&curstringtree->mtext,text); + FieldArrayAddDynamicValueConcat(&curstringtree->replace,&curstringtree->nreplace,&curstringtree->mreplace,replace); + } +} + +void FreeTextTreeRecurse(struct s_crcstring_tree *lt) +{ + #undef FUNC + #define FUNC "FreeTextTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeTextTreeRecurse(lt->radix[i]); + } + } + if (lt->mtext) { + for (i=0;i<lt->ntext;i++) MemFree(lt->text[i]); + MemFree(lt->text); + } + MemFree(lt); +} +void FreeTextTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeTextTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->stringtree.radix[i]) { + FreeTextTreeRecurse(ae->stringtree.radix[i]); + } + } + if (ae->stringtree.mtext) MemFree(ae->stringtree.text); +} +int SearchText(struct s_assenv *ae, char *text, int crc) +{ + #undef FUNC + #define FUNC "SearchText" + + struct s_crcstring_tree *curstringtree; + int i,radix,dek=32; + + curstringtree=&ae->stringtree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curstringtree->radix[radix]) { + curstringtree=curstringtree->radix[radix]; + } else { + /* radix not found, used is not in index */ + return 0; + } + } + for (i=0;i<curstringtree->ntext;i++) { + if (strcmp(curstringtree->text[i],text)==0) { + return 1; + } + } + return 0; +} + + + + + + + +/* +struct s_crclabel_tree { + + + + +/* +struct s_crclabel_tree { + struct s_crclabel_tree *radix[256]; + struct s_label *label; + int nlabel,mlabel; +}; +*/ +void FreeLabelTreeRecurse(struct s_crclabel_tree *lt) +{ + #undef FUNC + #define FUNC "FreeLabelTreeRecurse" + + int i; + + for (i=0;i<256;i++) { + if (lt->radix[i]) { + FreeLabelTreeRecurse(lt->radix[i]); + } + } + /* label.name already freed elsewhere as this one is a copy */ + if (lt->mlabel) MemFree(lt->label); + MemFree(lt); +} +void FreeLabelTree(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "FreeLabelTree" + + int i; + + for (i=0;i<256;i++) { + if (ae->labeltree.radix[i]) { + FreeLabelTreeRecurse(ae->labeltree.radix[i]); + } + } + if (ae->labeltree.mlabel) MemFree(ae->labeltree.label); +} + +struct s_label *SearchLabel(struct s_assenv *ae, char *label, int crc) +{ + #undef FUNC + #define FUNC "SearchLabel" + + struct s_crclabel_tree *curlabeltree; + struct s_label *retlabel=NULL; + int i,radix,dek=32; +//printf("searchLabel [%s]",label); + curlabeltree=&ae->labeltree; + while (dek) { + dek=dek-8; + radix=(crc>>dek)&0xFF; + if (curlabeltree->radix[radix]) { + curlabeltree=curlabeltree->radix[radix]; + } else { + /* radix not found, label is not in index */ +//printf(" not found\n"); + return NULL; + } + } + for (i=0;i<curlabeltree->nlabel;i++) { + if (!curlabeltree->label[i].name && strcmp(ae->wl[curlabeltree->label[i].iw].w,label)==0) { + curlabeltree->label[i].used=1; +//printf(" found (global)\n"); + return &curlabeltree->label[i]; + } else if (curlabeltree->label[i].name && strcmp(curlabeltree->label[i].name,label)==0) { + curlabeltree->label[i].used=1; +//printf(" found (local or proximity)\n"); + return &curlabeltree->label[i]; + } + } + return NULL; +} + +char *MakeLocalLabel(struct s_assenv *ae,char *varbuffer, int *retdek) +{ + #undef FUNC + #define FUNC "MakeLocalLabel" + + char *locallabel; + char hexdigit[32]; + int lenbuf=0,dek,i,im; + char *zepoint; + + lenbuf=strlen(varbuffer); + + /* not so local labels */ + if (varbuffer[0]=='.') { + /* create reference */ + if (ae->lastgloballabel) { + locallabel=MemMalloc(strlen(varbuffer)+1+ae->lastgloballabellen); + sprintf(locallabel,"%s%s",ae->lastgloballabel,varbuffer); + if (retdek) *retdek=0; + return locallabel; + } else { + if (retdek) *retdek=0; + return TxtStrDup(varbuffer); + } + } + + /*************************************************** + without retdek -> build a local label + with retdek -> build the hash string + ***************************************************/ + if (!retdek) { + locallabel=MemMalloc(lenbuf+(ae->ir+ae->iw+3)*8+8); + zepoint=strchr(varbuffer,'.'); + if (zepoint) { + *zepoint=0; + } + strcpy(locallabel,varbuffer); + } else { + locallabel=MemMalloc((ae->ir+ae->iw+3)*8+4); + locallabel[0]=0; + } +//printf("locallabel=[%s] (draft)\n",locallabel); + + dek=0; + dek+=strappend(locallabel,"R"); + for (i=0;i<ae->ir;i++) { + sprintf(hexdigit,"%04X",ae->repeat[i].cpt); + dek+=strappend(locallabel,hexdigit); + } + if (ae->ir) { + sprintf(hexdigit,"%04X",ae->repeat[ae->ir-1].value); + dek+=strappend(locallabel+dek,hexdigit); + } + + dek+=strappend(locallabel,"W"); + for (i=0;i<ae->iw;i++) { + sprintf(hexdigit,"%04X",ae->whilewend[i].cpt); + dek+=strappend(locallabel+dek,hexdigit); + } + if (ae->iw) { + sprintf(hexdigit,"%04X",ae->whilewend[ae->iw-1].value); + dek+=strappend(locallabel+dek,hexdigit); + } + /* where are we? */ + if (ae->imacropos) { + for (im=ae->imacropos-1;im>=0;im--) { + if (ae->idx>=ae->macropos[im].start && ae->idx<ae->macropos[im].end) break; + } + if (im>=0) { + /* si on n'est pas dans une macro, on n'indique rien */ + sprintf(hexdigit,"M%04X",ae->macropos[im].value); + dek+=strappend(locallabel+dek,hexdigit); + } + } + if (!retdek) { + if (zepoint) { + *zepoint='.'; + strcat(locallabel+dek,zepoint); + } + } else { + *retdek=dek; + } +//printf("locallabel=[%s] (end)\n",locallabel); + return locallabel; +} + +char *TradExpression(char *zexp) +{ + #undef FUNC + #define FUNC "TradExpression" + + static char *last_expression=NULL; + char *wstr; + + if (last_expression) {MemFree(last_expression);last_expression=NULL;} + if (!zexp) return NULL; + + wstr=TxtStrDup(zexp); + wstr=TxtReplace(wstr,"[","<<",0); + wstr=TxtReplace(wstr,"]",">>",0); + wstr=TxtReplace(wstr,"m","%",0); + + last_expression=wstr; + return wstr; +} + +int TrimFloatingPointString(char *fps) { + int i=0,pflag,zflag=0; + + while (fps[i]) { + if (fps[i]=='.') { + pflag=i; + zflag=1; + } else if (fps[i]!='0') { + zflag=0; + } + i++; + } + /* truncate floating fract */ + if (zflag) { + fps[pflag]=0; + } else { + pflag=i; + } + return pflag; +} + + + +/* + translate tag or formula between curly brackets + used in label declaration + used in print directive +*/ +char *TranslateTag(struct s_assenv *ae, char *varbuffer, int *touched, int enablefast, int tagoption) { + /******************************************************* + v a r i a b l e s i n s t r i n g s + *******************************************************/ + char *starttag,*endtag,*tagcheck,*expr; + int newlen,lenw,taglen,tagidx,tagcount,validx; + char curvalstr[256]={0}; + char *equpos=NULL,*equback; + +//printf("TranslateTag [%s]\n",varbuffer); + + if (tagoption & E_TAGOPTION_PRESERVE) { + if (ae->iw || ae->ir) { + /* inside a loop we must care about variables */ +//printf("TranslateTag [%s] with PRESERVE inside a loop!\n",varbuffer); + return varbuffer; + } + } + + *touched=0; + while ((starttag=strchr(varbuffer+1,'{'))!=NULL) { + if ((endtag=strchr(starttag,'}'))==NULL) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid tag in string [%s]\n",varbuffer); + return NULL; + } + /* allow inception */ + tagcount=1; + tagcheck=starttag+1; + while (*tagcheck && tagcount) { + if (*tagcheck=='}') tagcount--; else if (*tagcheck=='{') tagcount++; + tagcheck++; + } + if (tagcount) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid brackets combination in string [%s]\n",varbuffer); + return NULL; + } else { + endtag=tagcheck-1; + } + *touched=1; + taglen=endtag-starttag+1; + tagidx=starttag-varbuffer; + lenw=strlen(varbuffer); // before the EOF write + *endtag=0; + /*** c o m p u t e e x p r e s s i o n ***/ + expr=TxtStrDup(starttag+1); + if (tagoption & E_TAGOPTION_REMOVESPACE) expr=TxtReplace(expr," ","",0); + if (enablefast) ExpressionFastTranslate(ae,&expr,0); + validx=(int)RoundComputeExpressionCore(ae,expr,ae->codeadr,0); + if (validx<0) { + strcpy(curvalstr,""); + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"indexed tag must NOT be a negative value [%s]\n",varbuffer); + MemFree(expr); + return NULL; + } else { + #ifdef OS_WIN + snprintf(curvalstr,sizeof(curvalstr)-1,"%d",validx); + newlen=strlen(curvalstr); + #else + newlen=snprintf(curvalstr,sizeof(curvalstr)-1,"%d",validx); + #endif + } + MemFree(expr); + if (newlen>taglen) { + /* realloc */ + varbuffer=MemRealloc(varbuffer,lenw+newlen-taglen+1); + } + if (newlen!=taglen ) { + MemMove(varbuffer+tagidx+newlen,varbuffer+tagidx+taglen,lenw-taglen-tagidx+1); + } + strncpy(varbuffer+tagidx,curvalstr,newlen); /* copy without zero terminator */ + } + + return varbuffer; +} + +double ComputeExpressionCore(struct s_assenv *ae,char *original_zeexpression,int ptr, int didx) +{ + #undef FUNC + #define FUNC "ComputeExpressionCore" + + /* static execution buffers */ + static double *accu=NULL; + static int maccu=0; + static struct s_compute_element *computestack=NULL; + static int maxcomputestack=0; + int i,j,paccu=0; + int nbtokenstack=0; + int nbcomputestack=0; + int nboperatorstack=0; + + struct s_compute_element stackelement; + int o2,okclose,itoken; + + int idx=0,crc,icheck,is_binary,ivar=0; + char asciivalue[11]; + unsigned char c; + int accu_err=0; + /* backup alias replace */ + char *zeexpression,*expr; + int original=1; + int ialias,startvar; + int newlen,lenw; + /* dictionnary */ + struct s_expr_dico *curdic; + struct s_label *curlabel; + char *localname; + int minusptr,imkey,bank,page,idxmacro; + double curval; + /* negative value */ + int allow_minus_as_sign=0; + /* extended replace in labels */ + int curly=0,curlyflag=0; + char *Automate; + double dummint; + + /* memory cleanup */ + if (!ae) { + if (maccu) MemFree(accu); + accu=NULL;maccu=0; + if (maxcomputestack) MemFree(computestack); + computestack=NULL;maxcomputestack=0; +#if 0 + if (maxivar) MemFree(varbuffer); + if (maxtokenstack) MemFree(tokenstack); + if (maxoperatorstack) MemFree(operatorstack); + maxtokenstack=maxoperatorstack=0; + maxivar=1; + varbuffer=NULL; + tokenstack=NULL; + operatorstack=NULL; +#endif + return 0.0; + } + + /* be sure to have at least some bytes allocated */ + StateMachineResizeBuffer(&ae->computectx->varbuffer,128,&ae->computectx->maxivar); + + +#if TRACE_COMPUTE_EXPRESSION + printf("expression=[%s]\n",zeexpression); +#endif + zeexpression=original_zeexpression; + if (!zeexpression[0]) { + return 0; + } + /* double hack if the first value is negative */ + if (zeexpression[0]=='-') { + if (ae->AutomateExpressionValidCharFirst[(int)zeexpression[1]&0xFF]) { + allow_minus_as_sign=1; + } else { + memset(&stackelement,0,sizeof(stackelement)); + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + } + } + + /* is there ascii char? */ + while ((c=zeexpression[idx])!=0) { + if (c=='\'' || c=='"') { + /* echappement */ + if (zeexpression[idx+1]=='\\') { + if (zeexpression[idx+2] && zeexpression[idx+3]==c) { + sprintf(asciivalue,"#%03X",zeexpression[idx+2]); + memcpy(zeexpression+idx,asciivalue,4); + idx+=3; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Only single escaped char may be quoted [%s]\n",TradExpression(zeexpression)); + zeexpression[0]=0; + return 0; + } + } else if (zeexpression[idx+1] && zeexpression[idx+2]==c) { + sprintf(asciivalue,"#%02X",zeexpression[idx+1]); + memcpy(zeexpression+idx,asciivalue,3); + idx+=2; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Only single char may be quoted [%s]\n",TradExpression(zeexpression)); + zeexpression[0]=0; + return 0; + } + } + + idx++; + } +#if TRACE_COMPUTE_EXPRESSION + printf("apres conversion des chars [%s]\n",zeexpression); +#endif + /*********************************************************** + P A T C H F O R P O S I T I V E V A L U E + ***********************************************************/ + if (zeexpression[0]=='+') idx=1; else idx=0; + /*********************************************************** + C O M P U T E E X P R E S S I O N M A I N L O O P + ***********************************************************/ + while ((c=zeexpression[idx])!=0) { + switch (c) { + /* parenthesis */ + case ')': + /* next to a closing parenthesis, a minus is an operator */ + allow_minus_as_sign=0; + break; + case '(': + /* operator detection */ + case '*': + case '/': + case '^': + case '[': + case 'm': + case '+': + case ']': + allow_minus_as_sign=1; + break; + case '&': + allow_minus_as_sign=1; + if (c=='&' && zeexpression[idx+1]=='&') { + idx++; + c='a'; // boolean AND + } + break; + case '|': + allow_minus_as_sign=1; + if (c=='|' && zeexpression[idx+1]=='|') { + idx++; + c='o'; // boolean OR + } + break; + /* testing */ + case '<': + allow_minus_as_sign=1; + if (zeexpression[idx+1]=='=') { + idx++; + c='k'; // boolean LOWEREQ + } else if (zeexpression[idx+1]=='>') { + idx++; + c='n'; // boolean NOTEQUAL + } else { + c='l'; + } + break; + case '>': + allow_minus_as_sign=1; + if (zeexpression[idx+1]=='=') { + idx++; + c='h'; // boolean GREATEREQ + } else { + c='g'; + } + break; + case '!': + allow_minus_as_sign=1; + if (zeexpression[idx+1]=='=') { + idx++; + c='n'; // boolean NOTEQUAL + } else { + c='b'; + } + break; + case '=': + allow_minus_as_sign=1; + /* expecting == */ + if (zeexpression[idx+1]=='=') { + idx++; + c='e'; // boolean EQUAL + /* except in maxam mode with a single = */ + } else if (ae->maxam) { + c='e'; // boolean EQUAL + /* cannot affect data inside an expression */ + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot set variable inside an expression\n",TradExpression(zeexpression)); + return 0; + } + break; + case '-': + if (allow_minus_as_sign) { + /* previous char was an opening parenthesis or an operator */ + ivar=0; + ae->computectx->varbuffer[ivar++]='-'; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + c=zeexpression[++idx]; + if (ae->AutomateExpressionValidCharFirst[(int)c&0xFF]) { + ae->computectx->varbuffer[ivar++]=c; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + c=zeexpression[++idx]; + while (ae->AutomateExpressionValidChar[(int)c&0xFF]) { + ae->computectx->varbuffer[ivar++]=c; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + c=zeexpression[++idx]; + } + } + ae->computectx->varbuffer[ivar]=0; + if (ivar<2) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] invalid minus sign\n",TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } + break; + } + allow_minus_as_sign=1; + break; + + /* operator OR binary value */ + case '%': + /* % symbol may be a modulo or a binary literal value */ + is_binary=0; + for (icheck=1;zeexpression[idx+icheck];icheck++) { + switch (zeexpression[idx+icheck]) { + case '1': + case '0':/* still binary */ + is_binary=1; + break; + case '+': + case '-': + case '/': + case '*': + case '|': + case 'm': + case '%': + case '^': + case '&': + case '(': + case ')': + case '=': + case '<': + case '>': + case '!': + case '[': + case ']': + if (is_binary) is_binary=2; else is_binary=-1; + break; + default: + is_binary=-1; + } + if (is_binary==2) { + break; + } + if (is_binary==-1) { + is_binary=0; + break; + } + } + if (!is_binary) { + allow_minus_as_sign=1; + c='m'; + break; + } + default: + allow_minus_as_sign=0; + /* semantic analysis */ + startvar=idx; + ivar=0; + /* first char does not allow same chars as next chars */ + if (ae->AutomateExpressionValidCharFirst[((int)c)&0xFF]) { + ae->computectx->varbuffer[ivar++]=c; + if (c=='{') { + /* not a formula but only a prefix tag */ + curly++; + } + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + idx++; + c=zeexpression[idx]; + Automate=ae->AutomateExpressionValidChar; + while (Automate[((int)c)&0xFF]) { + if (c=='{') { + curly++; + curlyflag=1; + Automate=ae->AutomateExpressionValidCharExtended; + } else if (c=='}') { + curly--; + if (!curly) { + Automate=ae->AutomateExpressionValidChar; + } + } + ae->computectx->varbuffer[ivar++]=c; + StateMachineResizeBuffer(&ae->computectx->varbuffer,ivar,&ae->computectx->maxivar); + idx++; + c=zeexpression[idx]; + } + } + ae->computectx->varbuffer[ivar]=0; + if (!ivar) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"invalid char (%d=%c) expression [%s]\n",c,c>31?c:' ',TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } else if (curly) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"wrong curly brackets in expression [%s]\n",TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } + } + if (c && !ivar) idx++; + + /************************************ + S T A C K D I S P A T C H E R + ************************************/ + /* push operator or stack value */ + if (!ivar) { + /************************************ + O P E R A T O R + ************************************/ + stackelement=ae->AutomateElement[c]; + if (stackelement.operator>E_COMPUTE_OPERATION_GREATEREQ) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] has unknown operator %c (%d)\n",TradExpression(zeexpression),c>31?c:'.',c); + } + /* stackelement.value isn't used */ + } else { + /************************************ + V A L U E + ************************************/ +#if TRACE_COMPUTE_EXPRESSION + printf("value [%s]\n",ae->computectx->varbuffer); +#endif + if (ae->computectx->varbuffer[0]=='-') minusptr=1; else minusptr=0; + /* constantes ou variables/labels */ + switch (ae->computectx->varbuffer[minusptr]) { + case '0': + /* 0x hexa value hack */ + if (ae->computectx->varbuffer[minusptr+1]=='X' && ae->AutomateHexa[ae->computectx->varbuffer[minusptr+2]]) { + for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,16); + break; + } else + /* 0b binary value hack */ + if (ae->computectx->varbuffer[minusptr+1]=='B' && (ae->computectx->varbuffer[minusptr+2]>='0' && ae->computectx->varbuffer[minusptr+2]<='1')) { + for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='1') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,2); + break; + } + /* 0o octal value hack */ + if (ae->computectx->varbuffer[minusptr+1]=='O' && (ae->computectx->varbuffer[minusptr+2]>='0' && ae->computectx->varbuffer[minusptr+2]<='5')) { + for (icheck=minusptr+3;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='5') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid octal number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+2,NULL,2); + break; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* check number */ + for (icheck=minusptr;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateDigit[ae->computectx->varbuffer[icheck]]) continue; + /* Intel hexa & binary style */ + switch (ae->computectx->varbuffer[strlen(ae->computectx->varbuffer)-1]) { + case 'H': + for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { + if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + curval=strtol(ae->computectx->varbuffer+minusptr,NULL,16); + break; + case 'B': + for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { + if (ae->computectx->varbuffer[icheck]=='0' || ae->computectx->varbuffer[icheck]=='1') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + curval=strtol(ae->computectx->varbuffer+minusptr,NULL,2); + break; + default: + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + icheck=0; + break; + } + if (!ae->computectx->varbuffer[icheck]) curval=atof(ae->computectx->varbuffer+minusptr); + break; + case '%': + /* check number */ + if (!ae->computectx->varbuffer[minusptr+1]) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an empty binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + for (icheck=minusptr+1;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]=='0' || ae->computectx->varbuffer[icheck]=='1') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid binary number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,2); + break; + case '#': + /* check number */ + if (!ae->computectx->varbuffer[minusptr+1]) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an empty hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + for (icheck=minusptr+1;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,16); + break; + default: + if (1 || !curlyflag) { + /* $ hex value hack */ + if (ae->computectx->varbuffer[minusptr+0]=='$' && ae->AutomateHexa[ae->computectx->varbuffer[minusptr+1]]) { + for (icheck=minusptr+2;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid hex number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,16); + break; + } + /* @ octal value hack */ + if (ae->computectx->varbuffer[minusptr+0]=='@' && ((ae->computectx->varbuffer[minusptr+1]>='0' && ae->computectx->varbuffer[minusptr+1]<='7'))) { + for (icheck=minusptr+2;ae->computectx->varbuffer[icheck];icheck++) { + if (ae->computectx->varbuffer[icheck]>='0' && ae->computectx->varbuffer[icheck]<='7') continue; + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is not a valid octal number\n",TradExpression(zeexpression),ae->computectx->varbuffer); + break; + } + curval=strtol(ae->computectx->varbuffer+minusptr+1,NULL,8); + break; + } + /* Intel hexa value hack */ + if (ae->AutomateHexa[ae->computectx->varbuffer[minusptr+0]]) { + if (ae->computectx->varbuffer[strlen(ae->computectx->varbuffer)-1]=='H') { + for (icheck=minusptr;ae->computectx->varbuffer[icheck+1];icheck++) { + if (!ae->AutomateHexa[ae->computectx->varbuffer[icheck]]) break; + } + if (!ae->computectx->varbuffer[icheck+1]) { + curval=strtol(ae->computectx->varbuffer+minusptr,NULL,16); + break; + } + } + } + } + + + if (curlyflag) { + char *minivarbuffer; + int touched; + + /* besoin d'un sous-contexte */ + minivarbuffer=TxtStrDup(ae->computectx->varbuffer+minusptr); + ae->computectx=&ae->ctx2; +#if TRACE_COMPUTE_EXPRESSION + printf("curly [%s]\n",minivarbuffer); +#endif + minivarbuffer=TranslateTag(ae,minivarbuffer, &touched,0,E_TAGOPTION_NONE); +#if TRACE_COMPUTE_EXPRESSION + printf("après curly [%s]\n",minivarbuffer); +#endif + ae->computectx=&ae->ctx1; + if (!touched) { + strcpy(ae->computectx->varbuffer+minusptr,minivarbuffer); + } else { + StateMachineResizeBuffer(&ae->computectx->varbuffer,strlen(minivarbuffer)+2,&ae->computectx->maxivar); + strcpy(ae->computectx->varbuffer+minusptr,minivarbuffer); + } + MemFree(minivarbuffer); + curlyflag=0; + } + + crc=GetCRC(ae->computectx->varbuffer+minusptr); + /*************************************************** + L O O K I N G F O R A F U N C T I O N + ***************************************************/ + for (imkey=0;math_keyword[imkey].mnemo[0];imkey++) { + if (crc==math_keyword[imkey].crc && strcmp(ae->computectx->varbuffer+minusptr,math_keyword[imkey].mnemo)==0) { + if (c=='(') { + /* push function as operator! */ + stackelement.operator=math_keyword[imkey].operation; + //stackelement.priority=0; + /************************************************ + C R E A T E E X T R A T O K E N + ************************************************/ + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + stackelement.operator=E_COMPUTE_OPERATION_OPEN; + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + allow_minus_as_sign=1; + idx++; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is a reserved keyword!\n",TradExpression(zeexpression),math_keyword[imkey].mnemo); + curval=0; + idx++; + } + ivar=0; + break; + } + } + if (math_keyword[imkey].mnemo[0]) continue; + + if (ae->computectx->varbuffer[minusptr+0]=='$' && ae->computectx->varbuffer[minusptr+1]==0) { + curval=ptr; + } else { +#if TRACE_COMPUTE_EXPRESSION + printf("search dico [%s]\n",ae->computectx->varbuffer+minusptr); +#endif + curdic=SearchDico(ae,ae->computectx->varbuffer+minusptr,crc); + if (curdic) { +#if TRACE_COMPUTE_EXPRESSION + printf("trouvé valeur=%.2lf\n",curdic->v); +#endif + curval=curdic->v; + break; + } else { + /* getbank hack */ + if (ae->computectx->varbuffer[minusptr]!='{') { + bank=0; + page=0; + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{BANK}",6)==0) { + bank=6; + page=0; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{PAGE}",6)==0) { + bank=6; + page=1; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{PAGESET}",9)==0) { + bank=9; + page=2; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + } else if (strncmp(ae->computectx->varbuffer+minusptr,"{SIZEOF}",8)==0) { + bank=8; + page=3; + /* obligé de recalculer le CRC */ + crc=GetCRC(ae->computectx->varbuffer+minusptr+bank); + /* search in structures prototypes and subfields */ + for (i=0;i<ae->irasmstruct;i++) { + if (ae->rasmstruct[i].crc==crc && strcmp(ae->rasmstruct[i].name,ae->computectx->varbuffer+minusptr+bank)==0) { + curval=ae->rasmstruct[i].size; + break; + } + + for (j=0;j<ae->rasmstruct[i].irasmstructfield;j++) { + if (ae->rasmstruct[i].rasmstructfield[j].crc==crc && strcmp(ae->rasmstruct[i].rasmstructfield[j].fullname,ae->computectx->varbuffer+minusptr+bank)==0) { + curval=ae->rasmstruct[i].rasmstructfield[j].size; + i=ae->irasmstruct+1; + break; + } + } + } + + if (i==ae->irasmstruct) { + /* search in structures aliases */ + for (i=0;i<ae->irasmstructalias;i++) { + if (ae->rasmstructalias[i].crc==crc && strcmp(ae->rasmstructalias[i].name,ae->computectx->varbuffer+minusptr+bank)==0) { + curval=ae->rasmstructalias[i].size+ae->rasmstructalias[i].ptr; + break; + } + } + if (i==ae->irasmstructalias) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot SIZEOF unknown structure [%s]!\n",ae->computectx->varbuffer+minusptr+bank); + curval=0; + } + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] - %s is an unknown prefix!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + } + /* limited label translation while processing crunched blocks + ae->curlz == current crunched block processed + expression->crunch_block=0 -> oui + expression->crunch_block=1 -> oui si même block + expression->crunch_block=2 -> non car sera relogée + */ + if (page!=3) { + +#if TRACE_COMPUTE_EXPRESSION +printf("search label [%s]\n",ae->computectx->varbuffer+minusptr+bank); +#endif + curlabel=SearchLabel(ae,ae->computectx->varbuffer+minusptr+bank,crc); + if (curlabel) { + if (ae->stage<2) { + if (curlabel->lz==-1) { + if (!bank) { + curval=curlabel->ptr; + } else { +#if TRACE_COMPUTE_EXPRESSION +printf("page=%d | ptr=%X ibank=%d\n",page,curlabel->ptr,curlabel->ibank); +#endif + switch (page) { + case 2: /* PAGESET */ + if (curlabel->ibank<BANK_MAX_NUMBER) { + curval=ae->setgate[curlabel->ibank]; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 1:/* PAGE */ + if (curlabel->ibank<BANK_MAX_NUMBER) { + /* 4M expansion compliant */ + if (ae->bankset[curlabel->ibank>>2]) { + curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; + } else { + curval=ae->bankgate[curlabel->ibank]; + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 0: + curval=curlabel->ibank; + break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); + } + } + } else { + /* label MUST be in the crunched block */ + if (curlabel->iorgzone==ae->expression[didx].iorgzone && curlabel->ibank==ae->expression[didx].ibank && curlabel->lz<=ae->expression[didx].lz) { + if (!bank) { + curval=curlabel->ptr; + } else { + if (page) { + switch (page) { + case 2: /* PAGESET */ + if (curlabel->ibank<BANK_MAX_NUMBER) { + /* 4M expansion compliant */ + curval=ae->setgate[curlabel->ibank]; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 1: /* PAGE */ + if (curlabel->ibank<BANK_MAX_NUMBER) { + /* 4M expansion compliant */ + if (ae->bankset[curlabel->ibank>>2]) { + curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; + } else { + curval=ae->bankgate[curlabel->ibank]; + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 0:curval=curlabel->ibank;break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); + } + } + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Label [%s](%d) cannot be computed because it is located after the crunched zone %d\n",ae->computectx->varbuffer,curlabel->lz,ae->expression[didx].lz); + curval=0; + } + } + } else { +#if TRACE_COMPUTE_EXPRESSION +printf("stage 2 | page=%d | ptr=%X ibank=%d\n",page,curlabel->ptr,curlabel->ibank); +#endif + if (bank) { + //curval=curlabel->ibank; + switch (page) { + case 2: /* PAGESET */ + if (curlabel->ibank<BANK_MAX_NUMBER) { + curval=ae->setgate[curlabel->ibank]; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGESET - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 1:/* PAGE */ + if (curlabel->ibank<BANK_MAX_NUMBER) { + /* 4M expansion compliant */ + if (ae->bankset[curlabel->ibank>>2]) { + curval=ae->bankgate[(curlabel->ibank&0x1FC)+(curlabel->ptr>>14)]; + } else { + curval=ae->bankgate[curlabel->ibank]; + } + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] cannot use PAGE - label [%s] is in a temporary space!\n",TradExpression(zeexpression),ae->computectx->varbuffer); + curval=curlabel->ibank; + } + break; + case 0: + curval=curlabel->ibank; + break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL ERROR (unknown paging)\n",GetExpFile(ae,didx),GetExpLine(ae,didx));FreeAssenv(ae);exit(-664); + } + } else { + curval=curlabel->ptr; + } + } + } else { + /*********** + to allow aliases declared after use + ***********/ + if ((ialias=SearchAlias(ae,crc,ae->computectx->varbuffer+minusptr))>=0) { + newlen=ae->alias[ialias].len; + lenw=strlen(zeexpression); + if (newlen>ivar) { + /* realloc bigger */ + if (original) { + expr=MemMalloc(lenw+newlen-ivar+1); + memcpy(expr,zeexpression,lenw+1); + zeexpression=expr; + original=0; + } else { + zeexpression=MemRealloc(zeexpression,lenw+newlen-ivar+1); + } + } + /* startvar? */ + if (newlen!=ivar) { + MemMove(zeexpression+startvar+newlen,zeexpression+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(zeexpression+startvar,ae->alias[ialias].translation,newlen); /* copy without zero terminator */ + idx=startvar; + ivar=0; + continue; + } else { + /* index possible sur une struct? */ + int reverse_idx,validx=-1; + char *structlabel; + + reverse_idx=strlen(ae->computectx->varbuffer)-1; + if (ae->computectx->varbuffer[reverse_idx]>='0' && ae->computectx->varbuffer[reverse_idx]<='9') { + /* vu que ça ne PEUT PAS être une valeur litérale, on ne fait pas de test de débordement */ + reverse_idx--; + while (ae->computectx->varbuffer[reverse_idx]>='0' && ae->computectx->varbuffer[reverse_idx]<='9') { + reverse_idx--; + } + reverse_idx++; + validx=atoi(ae->computectx->varbuffer+reverse_idx); + structlabel=TxtStrDup(ae->computectx->varbuffer+minusptr); + structlabel[reverse_idx-minusptr]=0; +#ifdef TRACE_STRUCT + printf("EVOL 119 -> looking for struct %s IDX=%d\n",structlabel,validx); +#endif + /* unoptimized search in structures aliases */ + crc=GetCRC(structlabel); + for (i=0;i<ae->irasmstructalias;i++) { + if (ae->rasmstructalias[i].crc==crc && strcmp(ae->rasmstructalias[i].name,structlabel)==0) { +#ifdef TRACE_STRUCT + printf("EVOL 119 -> found! ptr=%d size=%d\n",ae->rasmstructalias[i].ptr,ae->rasmstructalias[i].size); +#endif + curval=ae->rasmstructalias[i].size*validx+ae->rasmstructalias[i].ptr; + if (validx>=ae->rasmstructalias[i].nbelem) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: index out of array size!\n",GetExpFile(ae,didx),GetExpLine(ae,didx)); + } + break; + } + } + if (i==ae->irasmstructalias) { + /* not found */ + validx=-1; + } + MemFree(structlabel); + } + if (validx<0) { + /* last chance to get a keyword */ + if (strcmp(ae->computectx->varbuffer+minusptr,"REPEAT_COUNTER")==0) { + if (ae->ir) { + curval=ae->repeat[ae->ir-1].repeat_counter; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use REPEAT_COUNTER keyword outside a repeat loop\n"); + curval=0; + } + } else if (strcmp(ae->computectx->varbuffer+minusptr,"WHILE_COUNTER")==0) { + if (ae->iw) { + curval=ae->whilewend[ae->iw-1].while_counter; + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use WHILE_COUNTER keyword outside a while loop\n"); + curval=0; + } + } else { + /* in case the expression is a register */ + if (IsRegister(ae->computectx->varbuffer+minusptr)) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"cannot use register %s in this context\n",TradExpression(zeexpression)); + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"expression [%s] keyword [%s] not found in variables, labels or aliases\n",TradExpression(zeexpression),ae->computectx->varbuffer+minusptr); + if (ae->extended_error) { + char *lookstr; + lookstr=StringLooksLike(ae,ae->computectx->varbuffer+minusptr); + if (lookstr) { + rasm_printf(ae,KERROR" did you mean [%s] ?\n",lookstr); + } + } + } + + curval=0; + } + } + } + } + } + } + } + } + if (minusptr) curval=-curval; + stackelement.operator=E_COMPUTE_OPERATION_PUSH_DATASTC; + stackelement.value=curval; + /* priority isn't used */ + + allow_minus_as_sign=0; + ivar=0; + } + /************************************ + C R E A T E T O K E N + ************************************/ + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->tokenstack,&nbtokenstack,&ae->computectx->maxtokenstack,&stackelement,sizeof(stackelement)); + } + /******************************************************* + C R E A T E E X E C U T I O N S T A C K + *******************************************************/ +#define DEBUG_STACK 0 +#if DEBUG_STACK + for (itoken=0;itoken<nbtokenstack;itoken++) { + switch (ae->computectx->tokenstack[itoken].operator) { + case E_COMPUTE_OPERATION_PUSH_DATASTC:printf("%lf ",ae->computectx->tokenstack[itoken].value);break; + case E_COMPUTE_OPERATION_OPEN:printf("(");break; + case E_COMPUTE_OPERATION_CLOSE:printf(")");break; + case E_COMPUTE_OPERATION_ADD:printf("+ ");break; + case E_COMPUTE_OPERATION_SUB:printf("- ");break; + case E_COMPUTE_OPERATION_DIV:printf("/ ");break; + case E_COMPUTE_OPERATION_MUL:printf("* ");break; + case E_COMPUTE_OPERATION_AND:printf("and ");break; + case E_COMPUTE_OPERATION_OR:printf("or ");break; + case E_COMPUTE_OPERATION_MOD:printf("mod ");break; + case E_COMPUTE_OPERATION_XOR:printf("xor ");break; + case E_COMPUTE_OPERATION_NOT:printf("! ");break; + case E_COMPUTE_OPERATION_SHL:printf("<< ");break; + case E_COMPUTE_OPERATION_SHR:printf(">> ");break; + case E_COMPUTE_OPERATION_BAND:printf("&& ");break; + case E_COMPUTE_OPERATION_BOR:printf("|| ");break; + case E_COMPUTE_OPERATION_LOWER:printf("< ");break; + case E_COMPUTE_OPERATION_GREATER:printf("> ");break; + case E_COMPUTE_OPERATION_EQUAL:printf("== ");break; + case E_COMPUTE_OPERATION_NOTEQUAL:printf("!= ");break; + case E_COMPUTE_OPERATION_LOWEREQ:printf("<= ");break; + case E_COMPUTE_OPERATION_GREATEREQ:printf(">= ");break; + case E_COMPUTE_OPERATION_SIN:printf("sin ");break; + case E_COMPUTE_OPERATION_COS:printf("cos ");break; + case E_COMPUTE_OPERATION_INT:printf("int ");break; + case E_COMPUTE_OPERATION_FLOOR:printf("floor ");break; + case E_COMPUTE_OPERATION_ABS:printf("abs ");break; + case E_COMPUTE_OPERATION_LN:printf("ln ");break; + case E_COMPUTE_OPERATION_LOG10:printf("log10 ");break; + case E_COMPUTE_OPERATION_SQRT:printf("sqrt ");break; + case E_COMPUTE_OPERATION_ASIN:printf("asin ");break; + case E_COMPUTE_OPERATION_ACOS:printf("acos ");break; + case E_COMPUTE_OPERATION_ATAN:printf("atan ");break; + case E_COMPUTE_OPERATION_EXP:printf("exp ");break; + case E_COMPUTE_OPERATION_LOW:printf("low ");break; + case E_COMPUTE_OPERATION_HIGH:printf("high ");break; + case E_COMPUTE_OPERATION_PSG:printf("psg ");break; + case E_COMPUTE_OPERATION_RND:printf("rnd ");break; + case E_COMPUTE_OPERATION_FRAC:printf("frac ");break; + case E_COMPUTE_OPERATION_CEIL:printf("ceil ");break; + case E_COMPUTE_OPERATION_GET_R:printf("get_r ");break; + case E_COMPUTE_OPERATION_GET_V:printf("get_v ");break; + case E_COMPUTE_OPERATION_GET_B:printf("get_b ");break; + case E_COMPUTE_OPERATION_SET_R:printf("set_r ");break; + case E_COMPUTE_OPERATION_SET_V:printf("set_v ");break; + case E_COMPUTE_OPERATION_SET_B:printf("set_b ");break; + default:printf("bug\n");break; + } + + } + printf("\n"); +#endif + + for (itoken=0;itoken<nbtokenstack;itoken++) { + switch (ae->computectx->tokenstack[itoken].operator) { + case E_COMPUTE_OPERATION_PUSH_DATASTC: +#if DEBUG_STACK +printf("data\n"); +#endif + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); + break; + case E_COMPUTE_OPERATION_OPEN: + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); +#if DEBUG_STACK +printf("ajout (\n"); +#endif + break; + case E_COMPUTE_OPERATION_CLOSE: +#if DEBUG_STACK +printf("close\n"); +#endif + /* pop out token until the opened parenthesis is reached */ + o2=nboperatorstack-1; + okclose=0; + while (o2>=0) { + if (ae->computectx->operatorstack[o2].operator!=E_COMPUTE_OPERATION_OPEN) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); + nboperatorstack--; +#if DEBUG_STACK +printf("op--\n"); +#endif + o2--; + } else { + /* discard opening parenthesis as operator */ +#if DEBUG_STACK +printf("discard )\n"); +#endif + nboperatorstack--; + okclose=1; + o2--; + break; + } + } + if (!okclose) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"missing parenthesis [%s]\n",TradExpression(zeexpression)); + if (!original) { + MemFree(zeexpression); + } + return 0; + } + /* if upper token is a function then pop from the stack */ + if (o2>=0 && ae->computectx->operatorstack[o2].operator>=E_COMPUTE_OPERATION_SIN) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); + nboperatorstack--; +#if DEBUG_STACK +printf("pop function\n"); +#endif + } + break; + case E_COMPUTE_OPERATION_ADD: + case E_COMPUTE_OPERATION_SUB: + case E_COMPUTE_OPERATION_DIV: + case E_COMPUTE_OPERATION_MUL: + case E_COMPUTE_OPERATION_AND: + case E_COMPUTE_OPERATION_OR: + case E_COMPUTE_OPERATION_MOD: + case E_COMPUTE_OPERATION_XOR: + case E_COMPUTE_OPERATION_NOT: + case E_COMPUTE_OPERATION_SHL: + case E_COMPUTE_OPERATION_SHR: + case E_COMPUTE_OPERATION_BAND: + case E_COMPUTE_OPERATION_BOR: + case E_COMPUTE_OPERATION_LOWER: + case E_COMPUTE_OPERATION_GREATER: + case E_COMPUTE_OPERATION_EQUAL: + case E_COMPUTE_OPERATION_NOTEQUAL: + case E_COMPUTE_OPERATION_LOWEREQ: + case E_COMPUTE_OPERATION_GREATEREQ: +#if DEBUG_STACK +printf("operator\n"); +#endif + o2=nboperatorstack-1; + while (o2>=0 && ae->computectx->operatorstack[o2].operator!=E_COMPUTE_OPERATION_OPEN) { + if (ae->computectx->tokenstack[itoken].priority>=ae->computectx->operatorstack[o2].priority || ae->computectx->operatorstack[o2].operator>=E_COMPUTE_OPERATION_SIN) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[o2],sizeof(stackelement)); + nboperatorstack--; + o2--; + } else { + break; + } + } + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); + break; + case E_COMPUTE_OPERATION_SIN: + case E_COMPUTE_OPERATION_COS: + case E_COMPUTE_OPERATION_INT: + case E_COMPUTE_OPERATION_FLOOR: + case E_COMPUTE_OPERATION_ABS: + case E_COMPUTE_OPERATION_LN: + case E_COMPUTE_OPERATION_LOG10: + case E_COMPUTE_OPERATION_SQRT: + case E_COMPUTE_OPERATION_ASIN: + case E_COMPUTE_OPERATION_ACOS: + case E_COMPUTE_OPERATION_ATAN: + case E_COMPUTE_OPERATION_EXP: + case E_COMPUTE_OPERATION_LOW: + case E_COMPUTE_OPERATION_HIGH: + case E_COMPUTE_OPERATION_PSG: + case E_COMPUTE_OPERATION_RND: + case E_COMPUTE_OPERATION_FRAC: + case E_COMPUTE_OPERATION_CEIL: + case E_COMPUTE_OPERATION_GET_R: + case E_COMPUTE_OPERATION_GET_V: + case E_COMPUTE_OPERATION_GET_B: + case E_COMPUTE_OPERATION_SET_R: + case E_COMPUTE_OPERATION_SET_V: + case E_COMPUTE_OPERATION_SET_B: +#if DEBUG_STACK +printf("ajout de la fonction\n"); +#endif + ObjectArrayAddDynamicValueConcat((void **)&ae->computectx->operatorstack,&nboperatorstack,&ae->computectx->maxoperatorstack,&ae->computectx->tokenstack[itoken],sizeof(stackelement)); + break; + default:break; + } + } + /* pop remaining operators */ + while (nboperatorstack>0) { + ObjectArrayAddDynamicValueConcat((void **)&computestack,&nbcomputestack,&maxcomputestack,&ae->computectx->operatorstack[--nboperatorstack],sizeof(stackelement)); + } + + /******************************************** + E X E C U T E S T A C K + ********************************************/ + if (ae->maxam || ae->as80) { + int workinterval; + if (ae->as80) workinterval=0xFFFFFFFF; else workinterval=0xFFFF; + for (i=0;i<nbcomputestack;i++) { + switch (computestack[i].operator) { + /************************************************ + c a s e s s h o u l d b e s o r t e d + ************************************************/ + case E_COMPUTE_OPERATION_PUSH_DATASTC: + if (maccu<=paccu) { + maccu=16+paccu; + accu=MemRealloc(accu,sizeof(double)*maccu); + } + accu[paccu]=computestack[i].value;paccu++; + break; + case E_COMPUTE_OPERATION_OPEN: + case E_COMPUTE_OPERATION_CLOSE:/* cannot happend */ break; + case E_COMPUTE_OPERATION_ADD:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]+(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_SUB:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]-(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_MUL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]*(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_DIV:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]/(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_AND:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_OR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]|(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_XOR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]^(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_MOD:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]%(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_SHL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2])<<((int)accu[paccu-1]);paccu--;break; + case E_COMPUTE_OPERATION_SHR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2])>>((int)accu[paccu-1]);paccu--;break; + case E_COMPUTE_OPERATION_BAND:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&&(int)accu[paccu-1])&workinterval;paccu--;break; + case E_COMPUTE_OPERATION_BOR:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]||(int)accu[paccu-1])&workinterval;paccu--;break; + /* comparison */ + case E_COMPUTE_OPERATION_LOWER:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)<((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_LOWEREQ:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)<=((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_EQUAL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)==((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_NOTEQUAL:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)!=((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_GREATER:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)>((int)accu[paccu-1]&workinterval);paccu--;break; + case E_COMPUTE_OPERATION_GREATEREQ:if (paccu>1) accu[paccu-2]=((int)accu[paccu-2]&workinterval)>=((int)accu[paccu-1]&workinterval);paccu--;break; + /* functions */ + case E_COMPUTE_OPERATION_SIN:if (paccu>0) accu[paccu-1]=(int)sin(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_COS:if (paccu>0) accu[paccu-1]=(int)cos(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_ASIN:if (paccu>0) accu[paccu-1]=(int)asin(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ACOS:if (paccu>0) accu[paccu-1]=(int)acos(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ATAN:if (paccu>0) accu[paccu-1]=(int)atan(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_INT:break; + case E_COMPUTE_OPERATION_FLOOR:if (paccu>0) accu[paccu-1]=(int)floor(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_ABS:if (paccu>0) accu[paccu-1]=(int)fabs(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_EXP:if (paccu>0) accu[paccu-1]=(int)exp(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_LN:if (paccu>0) accu[paccu-1]=(int)log(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_LOG10:if (paccu>0) accu[paccu-1]=(int)log10(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_SQRT:if (paccu>0) accu[paccu-1]=(int)sqrt(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_LOW:if (paccu>0) accu[paccu-1]=((int)accu[paccu-1])&0xFF;break; + case E_COMPUTE_OPERATION_HIGH:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xFF00)>>8;break; + case E_COMPUTE_OPERATION_PSG:if (paccu>0) accu[paccu-1]=ae->psgfine[((int)accu[paccu-1])&0xFF];break; + case E_COMPUTE_OPERATION_RND:if (paccu>0) accu[paccu-1]=rand()%((int)accu[paccu-1]);break; + case E_COMPUTE_OPERATION_FRAC:if (paccu>0) accu[paccu-1]=((int)(accu[paccu-1]-(int)accu[paccu-1]));break; + case E_COMPUTE_OPERATION_CEIL:if (paccu>0) accu[paccu-1]=(int)ceil(accu[paccu-1])&workinterval;break; + case E_COMPUTE_OPERATION_GET_R:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF0)>>4);break; + case E_COMPUTE_OPERATION_GET_V:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF00)>>8);break; + case E_COMPUTE_OPERATION_GET_B:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xF);break; + case E_COMPUTE_OPERATION_SET_R:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<4;break; + case E_COMPUTE_OPERATION_SET_V:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<8;break; + case E_COMPUTE_OPERATION_SET_B:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15);break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid computing state! (%d)\n",GetExpFile(ae,didx),GetExpLine(ae,didx),computestack[i].operator);paccu=0; + } + if (!paccu) { + if (zeexpression[0]=='&') { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s] Did you use & for an hexadecimal value?\n",TradExpression(zeexpression)); + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s]\n",TradExpression(zeexpression)); + } + accu_err=1; + break; + } + } + } else { + for (i=0;i<nbcomputestack;i++) { +#if 0 + int kk; + for (kk=0;kk<paccu;kk++) printf("stack[%d]=%lf\n",kk,accu[kk]); + if (computestack[i].operator==E_COMPUTE_OPERATION_PUSH_DATASTC) { + printf("pacc=%d push %.1lf\n",paccu,computestack[i].value); + } else { + printf("pacc=%d operation %s p=%d\n",paccu,computestack[i].operator==E_COMPUTE_OPERATION_MUL?"*": + computestack[i].operator==E_COMPUTE_OPERATION_ADD?"+": + computestack[i].operator==E_COMPUTE_OPERATION_DIV?"/": + computestack[i].operator==E_COMPUTE_OPERATION_SUB?"-": + computestack[i].operator==E_COMPUTE_OPERATION_BAND?"&&": + computestack[i].operator==E_COMPUTE_OPERATION_BOR?"||": + computestack[i].operator==E_COMPUTE_OPERATION_SHL?"<<": + computestack[i].operator==E_COMPUTE_OPERATION_SHR?">>": + computestack[i].operator==E_COMPUTE_OPERATION_LOWER?"<": + computestack[i].operator==E_COMPUTE_OPERATION_GREATER?">": + computestack[i].operator==E_COMPUTE_OPERATION_EQUAL?"==": + computestack[i].operator==E_COMPUTE_OPERATION_INT?"INT": + computestack[i].operator==E_COMPUTE_OPERATION_LOWEREQ?"<=": + computestack[i].operator==E_COMPUTE_OPERATION_GREATEREQ?">=": + computestack[i].operator==E_COMPUTE_OPERATION_OPEN?"(": + computestack[i].operator==E_COMPUTE_OPERATION_CLOSE?")": + "<autre>",computestack[i].priority); + } +#endif + switch (computestack[i].operator) { + case E_COMPUTE_OPERATION_PUSH_DATASTC: + if (maccu<=paccu) { + maccu=16+paccu; + accu=MemRealloc(accu,sizeof(double)*maccu); + } + accu[paccu]=computestack[i].value;paccu++; + break; + case E_COMPUTE_OPERATION_OPEN: + case E_COMPUTE_OPERATION_CLOSE: /* cannot happend */ break; + case E_COMPUTE_OPERATION_ADD:if (paccu>1) accu[paccu-2]+=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_SUB:if (paccu>1) accu[paccu-2]-=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_MUL:if (paccu>1) accu[paccu-2]*=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_DIV:if (paccu>1) accu[paccu-2]/=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_AND:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))&((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_OR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))|((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_XOR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))^((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_NOT:/* half operator, half function */ if (paccu>0) accu[paccu-1]=!((int)floor(accu[paccu-1]+0.5));break; + case E_COMPUTE_OPERATION_MOD:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))%((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_SHL:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))<<((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_SHR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))>>((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_BAND:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))&&((int)floor(accu[paccu-1]+0.5));paccu--;break; + case E_COMPUTE_OPERATION_BOR:if (paccu>1) accu[paccu-2]=((int)floor(accu[paccu-2]+0.5))||((int)floor(accu[paccu-1]+0.5));paccu--;break; + /* comparison */ + case E_COMPUTE_OPERATION_LOWER:if (paccu>1) accu[paccu-2]=accu[paccu-2]<accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_LOWEREQ:if (paccu>1) accu[paccu-2]=accu[paccu-2]<=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_EQUAL:if (paccu>1) accu[paccu-2]=fabs(accu[paccu-2]-accu[paccu-1])<0.000001;paccu--;break; + case E_COMPUTE_OPERATION_NOTEQUAL:if (paccu>1) accu[paccu-2]=accu[paccu-2]!=accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_GREATER:if (paccu>1) accu[paccu-2]=accu[paccu-2]>accu[paccu-1];paccu--;break; + case E_COMPUTE_OPERATION_GREATEREQ:if (paccu>1) accu[paccu-2]=accu[paccu-2]>=accu[paccu-1];paccu--;break; + /* functions */ + case E_COMPUTE_OPERATION_SIN:if (paccu>0) accu[paccu-1]=sin(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_COS:if (paccu>0) accu[paccu-1]=cos(accu[paccu-1]*3.1415926545/180.0);break; + case E_COMPUTE_OPERATION_ASIN:if (paccu>0) accu[paccu-1]=asin(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ACOS:if (paccu>0) accu[paccu-1]=acos(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_ATAN:if (paccu>0) accu[paccu-1]=atan(accu[paccu-1])*180.0/3.1415926545;break; + case E_COMPUTE_OPERATION_INT:if (paccu>0) accu[paccu-1]=floor(accu[paccu-1]+0.5);break; + case E_COMPUTE_OPERATION_FLOOR:if (paccu>0) accu[paccu-1]=floor(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_ABS:if (paccu>0) accu[paccu-1]=fabs(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_EXP:if (paccu>0) accu[paccu-1]=exp(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_LN:if (paccu>0) accu[paccu-1]=log(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_LOG10:if (paccu>0) accu[paccu-1]=log10(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_SQRT:if (paccu>0) accu[paccu-1]=sqrt(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_LOW:if (paccu>0) accu[paccu-1]=((int)floor(accu[paccu-1]+0.5))&0xFF;break; + case E_COMPUTE_OPERATION_HIGH:if (paccu>0) accu[paccu-1]=(((int)floor(accu[paccu-1]+0.5))&0xFF00)>>8;break; + case E_COMPUTE_OPERATION_PSG:if (paccu>0) accu[paccu-1]=ae->psgfine[((int)floor(accu[paccu-1]+0.5))&0xFF];break; + case E_COMPUTE_OPERATION_RND:if (paccu>0) accu[paccu-1]=rand()%((int)accu[paccu-1]);break; + case E_COMPUTE_OPERATION_FRAC:if (paccu>0) accu[paccu-1]=modf(accu[paccu-1],&dummint);break; + case E_COMPUTE_OPERATION_CEIL:if (paccu>0) accu[paccu-1]=ceil(accu[paccu-1]);break; + case E_COMPUTE_OPERATION_GET_R:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF0)>>4);break; + case E_COMPUTE_OPERATION_GET_V:if (paccu>0) accu[paccu-1]=((((int)accu[paccu-1])&0xF00)>>8);break; + case E_COMPUTE_OPERATION_GET_B:if (paccu>0) accu[paccu-1]=(((int)accu[paccu-1])&0xF);break; + case E_COMPUTE_OPERATION_SET_R:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<4;break; + case E_COMPUTE_OPERATION_SET_V:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15)<<8;break; + case E_COMPUTE_OPERATION_SET_B:if (paccu>0) accu[paccu-1]=MinMaxInt(accu[paccu-1],0,15);break; + default:MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid computing state! (%d)\n",GetExpFile(ae,didx),GetExpLine(ae,didx),computestack[i].operator);paccu=0; + } + if (!paccu) { + if (zeexpression[0]=='&') { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s] Did you use & for an hexadecimal value?\n",TradExpression(zeexpression)); + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation [%s]\n",TradExpression(zeexpression)); + } + accu_err=1; + break; + } + } + } + if (!original) { + MemFree(zeexpression); + } + if (paccu==1) { + return accu[0]; + } else if (!accu_err) { + if (paccu) { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operator\n"); + } else { + MakeError(ae,GetExpFile(ae,didx),GetExpLine(ae,didx),"Missing operand for calculation\n"); + } + return 0; + } else { + return 0; + } +} +int RoundComputeExpressionCore(struct s_assenv *ae,char *zeexpression,int ptr,int didx) { + return floor(ComputeExpressionCore(ae,zeexpression,ptr,didx)+ae->rough); +} + +void ExpressionSetDicoVar(struct s_assenv *ae,char *name, double v) +{ + #undef FUNC + #define FUNC "ExpressionSetDicoVar" + + struct s_expr_dico curdic; + curdic.name=TxtStrDup(name); + curdic.crc=GetCRC(name); + curdic.v=v; + curdic.iw=ae->idx; + curdic.autorise_export=ae->autorise_export; + //ObjectArrayAddDynamicValueConcat((void**)&ae->dico,&ae->idic,&ae->mdic,&curdic,sizeof(curdic)); + if (SearchLabel(ae,curdic.name,curdic.crc)) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot create variable [%s] as there is already a label with the same name\n",name); + MemFree(curdic.name); + return; + } + InsertDicoToTree(ae,&curdic); +} + +double ComputeExpression(struct s_assenv *ae,char *expr, int ptr, int didx, int expected_eval) +{ + #undef FUNC + #define FUNC "ComputeExpression" + + char *ptr_exp,*ptr_exp2,backupeval; + int crc,idic,idx=0,ialias,touched,hasformula=0; + double v,vl; + struct s_alias curalias; + struct s_expr_dico *curdic; + char *minibuffer; + + while (!ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) idx++; + + switch (ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) { + /***************************************** + M A K E A L I A S + *****************************************/ + case '~': + memset(&curalias,0,sizeof(curalias)); + ptr_exp=expr+idx; + *ptr_exp=0; // on scinde l'alias de son texte + ptr_exp2=ptr_exp+1; +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias (1) EXPR=[%s EQU %s]\n",expr,ptr_exp2); +#endif + + /* alias locaux ou de proximité */ + if (strchr("@.",expr[0])) { +#if TRACE_COMPUTE_EXPRESSION +printf("WARNING! alias is local! [%s]\n",expr); +#endif + /* local label creation does not handle formula in tags */ + curalias.alias=TranslateTag(ae,TxtStrDup(expr),&touched,0,E_TAGOPTION_NONE); + curalias.alias=MakeLocalLabel(ae,curalias.alias,NULL); + hasformula=1; + } else if (strchr(expr,'{')) { +#if TRACE_COMPUTE_EXPRESSION +printf("WARNING! alias has tag! [%s]\n",expr); +#endif + /* alias name contains formula */ + curalias.alias=TranslateTag(ae,TxtStrDup(expr),&touched,0,E_TAGOPTION_NONE); +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias (2) EXPR=[%s EQU %s]\n",expr,ptr_exp2); +#endif + hasformula=1; + } else { + curalias.alias=TxtStrDup(expr); + } + curalias.crc=GetCRC(curalias.alias); + if ((ialias=SearchAlias(ae,curalias.crc,curalias.alias))>=0) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Duplicate alias [%s]\n",expr); + MemFree(curalias.alias); + } else if (SearchDico(ae,curalias.alias,curalias.crc)) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Alias cannot override existing variable [%s]\n",expr); + MemFree(curalias.alias); + } else { + curalias.translation=MemMalloc(strlen(ptr_exp2)+1+2); + sprintf(curalias.translation,"(%s)",ptr_exp2); +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias (3) EXPR=[%s EQU %s]\n",expr,ptr_exp2); +printf("alias translation [%s] -> ",curalias.translation);fflush(stdout); +#endif + ExpressionFastTranslate(ae,&curalias.translation,2); // FAST type 2 +#if TRACE_COMPUTE_EXPRESSION +printf("%s\n",curalias.translation); +#endif + curalias.len=strlen(curalias.translation); + curalias.autorise_export=ae->autorise_export; + curalias.iw=ae->idx; + ObjectArrayAddDynamicValueConcat((void**)&ae->alias,&ae->ialias,&ae->malias,&curalias,sizeof(curalias)); + CheckAndSortAliases(ae); + } + *ptr_exp='~'; // on remet l'alias en place +#if TRACE_COMPUTE_EXPRESSION +printf("MakeAlias end with alias=[%s]=[%s]\n",curalias.alias,curalias.translation); +printf("***********\n"); +#endif + return 0; + /***************************************** + S E T V A R + *****************************************/ + case '=': + /* patch NOT */ + if (ae->AutomateExpressionDecision[((int)expr[idx+1])&0xFF]==0 || expr[idx+1]=='!') { + if (expected_eval) { + if (ae->maxam) { + /* maxam mode AND expected a value -> force comparison */ + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"meaningless use of an expression [%s]\n",expr); + return 0; + } + } else { + /* affectation */ + if ((expr[0]<'A' || expr[0]>'Z') && expr[0]!='_') { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"variable name must begin by a letter or '_' [%s]\n",expr); + return 0; + } else { + ptr_exp=expr+idx; + v=ComputeExpressionCore(ae,ptr_exp+1,ptr,didx); + *ptr_exp=0; + crc=GetCRC(expr); + if ((ialias=SearchAlias(ae,crc,expr))>=0) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Variable cannot override existing alias [%s]\n",expr); + return 0; + } + curdic=SearchDico(ae,expr,crc); + if (curdic) { + /* on affecte */ + curdic->v=v; + } else { + /* on cree une nouvelle variable */ + ExpressionSetDicoVar(ae,expr,v); + } + *ptr_exp='='; + return v; + } + } + } + break; + /***************************************** + P U R E E X P R E S S I O N + *****************************************/ + default:break; + } + return ComputeExpressionCore(ae,expr,ptr,didx); +} +int RoundComputeExpression(struct s_assenv *ae,char *expr, int ptr, int didx, int expression_expected) { + return floor(ComputeExpression(ae,expr,ptr,didx,expression_expected)+ae->rough); +} + +/* + ExpressionFastTranslate + + purpose: translate all known symbols in an expression (especially variables acting like counters) +*/ +void ExpressionFastTranslate(struct s_assenv *ae, char **ptr_expr, int fullreplace) +{ + #undef FUNC + #define FUNC "ExpressionFastTranslate" + + struct s_label *curlabel; + struct s_expr_dico *curdic; + static char *varbuffer=NULL; + static int ivar=0,maxivar=1; + char curval[256]={0}; + int c,lenw=0,idx=0,crc,startvar,newlen,ialias,found_replace,yves,dek,reidx,lenbuf,rlen,tagoffset; + double v; + char tmpuchar[16]; + char *expr,*locallabel; + int curly=0,curlyflag=0; + char *Automate; + int recurse=-1,recursecount=0; + + if (!ae || !ptr_expr) { + if (varbuffer) MemFree(varbuffer); + varbuffer=NULL; + maxivar=1; + ivar=0; + return; + } + /* be sure to have at least some bytes allocated */ + StateMachineResizeBuffer(&varbuffer,128,&maxivar); + expr=*ptr_expr; + +//printf("fast [%s]\n",expr); + + while (!ae->AutomateExpressionDecision[((int)expr[idx])&0xFF]) idx++; + + switch (ae->maxam) { + default: + case 0: /* full check */ + if (expr[idx]=='~' || (expr[idx]=='=' && expr[idx+1]!='=')) {reidx=idx+1;break;} + reidx=0; + break; + case 1: /* partial check with maxam */ + if (expr[idx]=='~') {reidx=idx+1;break;} + reidx=0; + break; + } + + idx=0; + /* is there ascii char? */ + while ((c=expr[idx])!=0) { + if (c=='\'' || c=='"') { + /* echappement */ + if (expr[idx+1]=='\\') { + if (expr[idx+2] && expr[idx+3]==c) { + /* no charset conversion for escaped chars */ + c=expr[idx+2]; + switch (c) { + case 'b':c='\b';break; + case 'v':c='\v';break; + case 'f':c='\f';break; + case '0':c='\0';break; + case 'r':c='\r';break; + case 'n':c='\n';break; + case 't':c='\t';break; + default:break; + } + sprintf(tmpuchar,"#%03X",c); + memcpy(expr+idx,tmpuchar,4); + idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] - Only single escaped char may be quoted\n",expr); + expr[0]=0; + return; + } + } else if (expr[idx+1] && expr[idx+2]==c) { + sprintf(tmpuchar,"#%02X",ae->charset[(int)expr[idx+1]]); + memcpy(expr+idx,tmpuchar,3); + idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] - Only single char may be quoted\n",expr); + expr[0]=0; + return; + } + } + idx++; + } + + idx=reidx; + while ((c=expr[idx])!=0) { + switch (c) { + /* operator / parenthesis */ + case '!': + case '=': + case '>': + case '<': + case '(': + case ')': + case ']': + case '[': + case '*': + case '/': + case '+': + case '~': + case '-': + case '^': + case 'm': + case '|': + case '&': + idx++; + break; + default: + startvar=idx; + if (ae->AutomateExpressionValidCharFirst[((int)c)&0xFF]) { + varbuffer[ivar++]=c; + if (c=='{') { + /* this is only tag and not a formula */ + curly++; + } + StateMachineResizeBuffer(&varbuffer,ivar,&maxivar); + idx++; + c=expr[idx]; + + Automate=ae->AutomateExpressionValidChar; + while (Automate[((int)c)&0xFF]) { + if (c=='{') { + curly++; + curlyflag=1; + Automate=ae->AutomateExpressionValidCharExtended; + } else if (c=='}') { + curly--; + if (!curly) { + Automate=ae->AutomateExpressionValidChar; + } + } + varbuffer[ivar++]=c; + StateMachineResizeBuffer(&varbuffer,ivar,&maxivar); + idx++; + c=expr[idx]; + } + } + varbuffer[ivar]=0; + if (!ivar) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"invalid expression [%s] c=[%c] idx=%d\n",expr,c,idx); + return; + } else if (curly) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"wrong curly brackets in expression [%s]\n",expr); + return; + } + } + if (ivar && (varbuffer[0]<'0' || varbuffer[0]>'9')) { + /* numbering var or label */ + if (curlyflag) { + char *minivarbuffer; + int touched; +//printf("ExpressionFastTranslate curly\n"); + minivarbuffer=TranslateTag(ae,TxtStrDup(varbuffer), &touched,0,E_TAGOPTION_NONE|(fullreplace?0:E_TAGOPTION_PRESERVE)); + StateMachineResizeBuffer(&varbuffer,strlen(minivarbuffer)+1,&maxivar); + strcpy(varbuffer,minivarbuffer); + newlen=strlen(varbuffer); + lenw=strlen(expr); + /* must update source */ + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + lenw=strlen(expr); + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,minivarbuffer,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + /***/ + MemFree(minivarbuffer); + curlyflag=0; + /******* ivar must be updated in case of label or alias following ***********/ + ivar=newlen; + } + + /* recherche dans dictionnaire et remplacement */ + crc=GetCRC(varbuffer); + found_replace=0; + /* pour les affectations ou les tests conditionnels on ne remplace pas le dico (pour le Push oui par contre!) */ + if (fullreplace) { + if (varbuffer[0]=='$' && !varbuffer[1]) { + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",ae->codeadr); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",ae->codeadr); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + ivar=0; + found_replace=1; + } else { + curdic=SearchDico(ae,varbuffer,crc); + if (curdic) { + v=curdic->v; +//printf("ExpressionFastTranslate (full) -> replace var (%s=%0.1lf)\n",varbuffer,v); + + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%lf",v); + newlen=TrimFloatingPointString(curval); + #else + snprintf(curval,sizeof(curval)-1,"%lf",v); + newlen=TrimFloatingPointString(curval); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + ivar=0; + found_replace=1; + } + } + } + /* on cherche aussi dans les labels existants */ + if (!found_replace) { + curlabel=SearchLabel(ae,varbuffer,crc); + if (curlabel) { + if (!curlabel->lz || ae->stage>1) { + yves=curlabel->ptr; + + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",yves); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + found_replace=1; + idx=startvar+newlen; + ivar=0; + } + } + } + /* non trouve on cherche dans les alias */ + if (!found_replace) { + if ((ialias=SearchAlias(ae,crc,varbuffer))>=0) { + newlen=ae->alias[ialias].len; + lenw=strlen(expr); + /* infinite replacement check */ + if (recurse<=startvar) { + /* recurse maximum count is a mix of alias len and alias number */ + if (recursecount>ae->ialias+ae->alias[ialias].len) { + if (strchr(expr,'~')!=NULL) *strchr(expr,'~')=0; + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"alias definition of %s has infinite recursivity\n",expr); + expr[0]=0; /* avoid some errors due to shitty definition */ + return; + } else { + recursecount++; + } + } + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + } + strncpy(expr+startvar,ae->alias[ialias].translation,newlen); /* copy without zero terminator */ + found_replace=1; + /* need to parse again alias because of delayed declarations */ + recurse=startvar; + idx=startvar; + ivar=0; + } else { + } + } + if (!found_replace) { + //printf("fasttranslate test local label\n"); + /* non trouve c'est peut-etre un label local - mais pas de l'octal */ + if (varbuffer[0]=='@' && (varbuffer[1]<'0' || varbuffer[1]>'9')) { + char *zepoint; + lenbuf=strlen(varbuffer); +//printf("MakeLocalLabel(ae,varbuffer,&dek); (1)\n"); + locallabel=MakeLocalLabel(ae,varbuffer,&dek); +//printf("exprin =[%s] rlen=%d dek-lenbuf=%d\n",expr,rlen,dek-lenbuf); + /*** le grand remplacement ***/ + /* local to macro or loop */ + rlen=strlen(expr+startvar+lenbuf)+1; + expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek+1); + /* move end of expression in order to insert local ID */ + zepoint=strchr(varbuffer,'.'); + if (zepoint) { + /* far proximity access */ + int suffixlen,dotpos; + dotpos=(zepoint-varbuffer); + suffixlen=lenbuf-dotpos; + + MemMove(expr+startvar+dotpos+dek,expr+startvar+dotpos,rlen+suffixlen); + strncpy(expr+startvar+dotpos,locallabel,dek); + } else { + /* legacy */ + MemMove(expr+startvar+lenbuf+dek,expr+startvar+lenbuf,rlen); + strncpy(expr+startvar+lenbuf,locallabel,dek); + } + idx+=dek; + MemFree(locallabel); + found_replace=1; +//printf("exprout=[%s]\n",expr); + } else if (varbuffer[0]=='.' && (varbuffer[1]<'0' || varbuffer[1]>'9')) { + /* proximity label */ + lenbuf=strlen(varbuffer); +//printf("MakeLocalLabel(ae,varbuffer,&dek); (2)\n"); + locallabel=MakeLocalLabel(ae,varbuffer,&dek); + /*** le grand remplacement ***/ + rlen=strlen(expr+startvar+lenbuf)+1; + dek=strlen(locallabel); +//printf("exprin =[%s] rlen=%d dek-lenbuf=%d\n",expr,rlen,dek-lenbuf); + expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek-lenbuf+1); + MemMove(expr+startvar+dek,expr+startvar+lenbuf,rlen); + strncpy(expr+startvar,locallabel,dek); + idx+=dek-lenbuf; + MemFree(locallabel); +//printf("exprout=[%s]\n",expr); + +//@@TODO ajouter une recherche d'alias? + + } else if (varbuffer[0]=='{') { + if (strncmp(varbuffer,"{BANK}",6)==0 || strncmp(varbuffer,"{PAGE}",6)==0) tagoffset=6; else + if (strncmp(varbuffer,"{PAGESET}",9)==0) tagoffset=9; else + if (strncmp(varbuffer,"{SIZEOF}",8)==0) tagoffset=8; else + { + tagoffset=0; + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Unknown prefix tag\n"); + } + + if (varbuffer[tagoffset]=='@') { + char *zepoint; + startvar+=tagoffset; + lenbuf=strlen(varbuffer+tagoffset); +//printf("MakeLocalLabel(ae,varbuffer,&dek); (3)\n"); + locallabel=MakeLocalLabel(ae,varbuffer+tagoffset,&dek); + /*** le grand remplacement ***/ + rlen=strlen(expr+startvar+lenbuf)+1; + expr=*ptr_expr=MemRealloc(expr,strlen(expr)+dek+1); + /* move end of expression in order to insert local ID */ + zepoint=strchr(varbuffer,'.'); + if (zepoint) { + /* far proximity access */ + int suffixlen,dotpos; + dotpos=(zepoint-varbuffer); + suffixlen=lenbuf-dotpos; + + MemMove(expr+startvar+dotpos+dek,expr+startvar+dotpos,rlen+suffixlen); + strncpy(expr+startvar+dotpos,locallabel,dek); + } else { + /* legacy */ + MemMove(expr+startvar+lenbuf+dek,expr+startvar+lenbuf,rlen); + strncpy(expr+startvar+lenbuf,locallabel,dek); + } + idx+=dek; + MemFree(locallabel); + found_replace=1; + } else if (varbuffer[tagoffset]=='$') { + int tagvalue=-1; + if (strcmp(varbuffer,"{BANK}$")==0) { + if (ae->forcecpr) { + if (ae->activebank<32) { + tagvalue=ae->activebank; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use BANK $ in a temporary space!\n",TradExpression(expr)); + tagvalue=0; + } + } else if (ae->forcesnapshot) { + if (ae->activebank<BANK_MAX_NUMBER) { + /* on autorise le préfixe BANK en snapshot avec une subtilité */ + if (ae->bankset[ae->activebank>>2]) { + tagvalue=ae->activebank+(ae->codeadr>>14); /* dans un bankset on tient compte de l'adresse */ + } else { + tagvalue=ae->activebank; + } + + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use BANK $ in a temporary space!\n",TradExpression(expr)); + tagvalue=0; + } + } + } else if (strcmp(varbuffer,"{PAGE}$")==0) { + if (ae->activebank<BANK_MAX_NUMBER) { + if (ae->bankset[ae->activebank>>2]) { + tagvalue=ae->bankgate[(ae->activebank&0x1FC)+(ae->codeadr>>14)]; + } else { + tagvalue=ae->bankgate[ae->activebank]; + } + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use PAGE $ in a temporary space!\n",TradExpression(expr)); + tagvalue=ae->activebank; + } + } else if (strcmp(varbuffer,"{PAGESET}$")==0) { + if (ae->activebank<BANK_MAX_NUMBER) { + tagvalue=ae->setgate[ae->activebank]; + //if (ae->activebank>3) tagvalue=((ae->activebank>>2)-1)*8+0xC2; else tagvalue=0xC0; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"expression [%s] cannot use PAGESET $ in a temporary space!\n",TradExpression(expr)); + tagvalue=ae->activebank; + } + } + /* replace */ + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",tagvalue); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",tagvalue); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + idx=startvar+newlen; + ivar=0; + found_replace=1; + } + } + } + + + + + + + if (!found_replace && strcmp(varbuffer,"REPEAT_COUNTER")==0) { + if (ae->ir) { + yves=ae->repeat[ae->ir-1].repeat_counter; + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",yves); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + found_replace=1; + idx=startvar+newlen; + ivar=0; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot use REPEAT_COUNTER outside repeat loop\n"); + } + } + if (!found_replace && strcmp(varbuffer,"WHILE_COUNTER")==0) { + if (ae->iw) { + yves=ae->whilewend[ae->iw-1].while_counter; + #ifdef OS_WIN + snprintf(curval,sizeof(curval)-1,"%d",yves); + newlen=strlen(curval); + #else + newlen=snprintf(curval,sizeof(curval)-1,"%d",yves); + #endif + lenw=strlen(expr); + if (newlen>ivar) { + /* realloc bigger */ + expr=*ptr_expr=MemRealloc(expr,lenw+newlen-ivar+1); + } + if (newlen!=ivar ) { + MemMove(expr+startvar+newlen,expr+startvar+ivar,lenw-startvar-ivar+1); + found_replace=1; + } + strncpy(expr+startvar,curval,newlen); /* copy without zero terminator */ + found_replace=1; + idx=startvar+newlen; + ivar=0; + } else { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"cannot use WHILE_COUNTER outside repeat loop\n"); + } + } + /* unknown symbol -> add to used symbol pool */ + if (!found_replace) { + InsertUsedToTree(ae,varbuffer,crc); + } + } + ivar=0; + } +} + +void PushExpression(struct s_assenv *ae,int iw,enum e_expression zetype) +{ + #undef FUNC + #define FUNC "PushExpression" + + struct s_expression curexp={0}; + int startptr=0; + + if (!ae->nocode) { + curexp.iw=iw; + curexp.wptr=ae->outputadr; + curexp.zetype=zetype; + curexp.ibank=ae->activebank; + curexp.iorgzone=ae->io-1; + curexp.lz=ae->lz; + /* on traduit de suite les variables du dictionnaire pour les boucles et increments + SAUF si c'est une affectation */ + if (!ae->wl[iw].e) { + switch (zetype) { + case E_EXPRESSION_V16C: + /* check non register usage */ + switch (GetCRC(ae->wl[iw].w)) { + case CRC_IX: + case CRC_IY: + case CRC_MIX: + case CRC_MIY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"invalid register usage\n",ae->maxptr); + default:break; + } + case E_EXPRESSION_J8: + case E_EXPRESSION_V8: + case E_EXPRESSION_V16: + case E_EXPRESSION_IM:startptr=-1; + break; + case E_EXPRESSION_IV8: + case E_EXPRESSION_IV81: + case E_EXPRESSION_IV16:startptr=-2; + break; + case E_EXPRESSION_3V8:startptr=-3; + break; + case E_EXPRESSION_RUN: + case E_EXPRESSION_ZXRUN: + case E_EXPRESSION_ZXSTACK: + default:break; + } + /* hack pourri pour gérer le $ */ + ae->codeadr+=startptr; + /* ok mais les labels locaux des macros? */ + if (ae->ir || ae->iw || ae->imacro) { + curexp.reference=TxtStrDup(ae->wl[iw].w); + ExpressionFastTranslate(ae,&curexp.reference,1); + } else { + ExpressionFastTranslate(ae,&ae->wl[iw].w,1); + } + ae->codeadr-=startptr; + } + /* calcul adresse de reference et post-incrementation pour sauter les data */ + switch (zetype) { + case E_EXPRESSION_J8:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V8:curexp.ptr=ae->codeadr;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_V8:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V16:curexp.ptr=ae->codeadr;ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_0V32:curexp.ptr=ae->codeadr;ae->outputadr+=4;ae->codeadr+=4;break; + case E_EXPRESSION_0VR:curexp.ptr=ae->codeadr;ae->outputadr+=5;ae->codeadr+=5;break; + case E_EXPRESSION_V16C: + case E_EXPRESSION_V16:curexp.ptr=ae->codeadr-1;ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_IV81:curexp.ptr=ae->codeadr-2;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV8:curexp.ptr=ae->codeadr-2;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_3V8:curexp.ptr=ae->codeadr-3;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV16:curexp.ptr=ae->codeadr-2;ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_RST:curexp.ptr=ae->codeadr;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IM:curexp.ptr=ae->codeadr-1;ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_RUN:break; + case E_EXPRESSION_ZXRUN:break; + case E_EXPRESSION_ZXSTACK:break; + } + /* le contrôle n'est pas bon avec les DEFB, DEFW, ... -> @@TODO */ + if (ae->outputadr<=ae->maxptr) { + ObjectArrayAddDynamicValueConcat((void **)&ae->expression,&ae->ie,&ae->me,&curexp,sizeof(curexp)); + } else { + /* to avoid double error message */ + if (!ae->stop) MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"output exceed limit %d\n",ae->maxptr); else MaxError(ae); + ae->stop=1; + return; + } + } else { + switch (zetype) { + case E_EXPRESSION_J8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_V8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_0V16:ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_0V32:ae->outputadr+=4;ae->codeadr+=4;break; + case E_EXPRESSION_0VR:ae->outputadr+=5;ae->codeadr+=5;break; + case E_EXPRESSION_V16C: + case E_EXPRESSION_V16:ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_IV81:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_3V8:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IV16:ae->outputadr+=2;ae->codeadr+=2;break; + case E_EXPRESSION_RST:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_IM:ae->outputadr++;ae->codeadr++;break; + case E_EXPRESSION_RUN:break; + case E_EXPRESSION_ZXRUN:break; + case E_EXPRESSION_ZXSTACK:break; + } + if (ae->outputadr<=ae->maxptr) { + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOCODE output exceed limit %d\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->maxptr); + FreeAssenv(ae);exit(3); + } + } +} + +/* +The CP/M 2.2 directory has only one type of entry: + +UU F1 F2 F3 F4 F5 F6 F7 F8 T1 T2 T3 EX S1 S2 RC .FILENAMETYP.... +AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL AL ................ + +UU = User number. 0-15 (on some systems, 0-31). The user number allows multiple + files of the same name to coexist on the disc. + User number = 0E5h => File deleted +Fn - filename +Tn - filetype. The characters used for these are 7-bit ASCII. + The top bit of T1 (often referred to as T1') is set if the file is + read-only. + T2' is set if the file is a system file (this corresponds to "hidden" on + other systems). +EX = Extent counter, low byte - takes values from 0-31 +S2 = Extent counter, high byte. + + An extent is the portion of a file controlled by one directory entry. + If a file takes up more blocks than can be listed in one directory entry, + it is given multiple entries, distinguished by their EX and S2 bytes. The + formula is: Entry number = ((32*S2)+EX) / (exm+1) where exm is the + extent mask value from the Disc Parameter Block. + +S1 - reserved, set to 0. +RC - Number of records (1 record=128 bytes) used in this extent, low byte. + The total number of records used in this extent is + + (EX & exm) * 128 + RC + + If RC is 80h, this extent is full and there may be another one on the disc. + File lengths are only saved to the nearest 128 bytes. + +AL - Allocation. Each AL is the number of a block on the disc. If an AL + number is zero, that section of the file has no storage allocated to it + (ie it does not exist). For example, a 3k file might have allocation + 5,6,8,0,0.... - the first 1k is in block 5, the second in block 6, the + third in block 8. + AL numbers can either be 8-bit (if there are fewer than 256 blocks on the + disc) or 16-bit (stored low byte first). +*/ +int EDSK_getblockid(int *fb) { + #undef FUNC + #define FUNC "EDSK_getblockid" + + int i; + for (i=0;i<180;i++) { + if (fb[i]) { + return i; + } + } + return -1; +} +int EDSK_getdirid(struct s_edsk_wrapper *curwrap) { + #undef FUNC + #define FUNC "EDSK_getdirid" + + int ie; + for (ie=0;ie<64;ie++) { + if (curwrap->entry[ie].user==0xE5) { +#if TRACE_EDSK + printf("getdirid returns %d\n",ie); +#endif + return ie; + } + } + return -1; +} +char *MakeAMSDOS_name(struct s_assenv *ae, char *filename) +{ + #undef FUNC + #define FUNC "MakeAMSDOS_name" + + static char amsdos_name[12]; + int i,ia; + char *pp; + /* warning */ + if (strlen(filename)>12) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning - filename [%s] too long for AMSDOS, will be truncated\n",filename); + } else if ((pp=strchr(filename,'.'))!=NULL) { + if (pp-filename>8) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning - filename [%s] too long for AMSDOS, will be truncated\n",filename); + } + } + /* copy filename */ + for (i=0;filename[i]!=0 && filename[i]!='.' && i<8;i++) { + amsdos_name[i]=toupper(filename[i]); + } + /* fill with spaces */ + for (ia=i;ia<8;ia++) { + amsdos_name[ia]=0x20; + } + /* looking for extension */ + for (;filename[i]!=0 && filename[i]!='.';i++); + /* then copy it if any */ + if (filename[i]=='.') { + i++; + for (ia=0;filename[i]!=0 && ia<3;ia++) { + amsdos_name[8+ia]=toupper(filename[i++]); + } + } + amsdos_name[11]=0; +#if TRACE_EDSK + printf("MakeAMSDOS_name [%s] -> [%s]\n",filename,amsdos_name); +#endif + return amsdos_name; +} + + +void EDSK_load(struct s_assenv *ae,struct s_edsk_wrapper *curwrap, char *edskfilename, int face) +{ + #undef FUNC + #define FUNC "EDSK_load" + + unsigned char header[256]; + unsigned char *data; + int tracknumber,sidenumber,tracksize,disksize; + int i,b,s,f,t,curtrack,sectornumber,sectorsize,sectorid,reallength; + int currenttrackposition=0,currentsectorposition,tmpcurrentsectorposition; + unsigned char checksectorid[9]; + int curblock=0,curoffset=0; +#if TRACE_EDSK + printf("EDSK_Load('%s',%d);",edskfilename,face); +#endif + if (FileReadBinary(edskfilename,(char*)&header,0x100)!=0x100) { + rasm_printf(ae,KERROR"Cannot read EDSK header of [%s]!\n",edskfilename); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (strncmp((char *)header,"MV - CPC",8)==0) { + rasm_printf(ae,KAYGREEN"updating DSK to EDSK [%s] / creator: %s",edskfilename,header+34); + + tracknumber=header[34+14]; + sidenumber=header[34+14+1]; + tracksize=header[34+14+1+1]+header[34+14+1+1+1]*256; + rasm_printf(ae,"tracks: %d sides:%d track size:%d",tracknumber,sidenumber,tracksize); + if (tracknumber>40 || sidenumber>2) { + rasm_printf(ae,KERROR"[%s] DSK format is not supported in update mode (ntrack=%d nside=%d)\n",edskfilename,tracknumber,sidenumber); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (face>=sidenumber) { + rasm_printf(ae,KWARNING"[%s] Warning - DSK has no face %d - DSK updated\n",edskfilename,face); + return; + } + + data=MemMalloc(tracksize*tracknumber*sidenumber); + memset(data,0,tracksize*tracknumber*sidenumber); + if (FileReadBinary(edskfilename,(char *)data,tracksize*tracknumber*sidenumber)!=tracksize*tracknumber*sidenumber) { + rasm_printf(ae,"Cannot read DSK tracks!"); + FreeAssenv(ae);exit(ABORT_ERROR); + } + //loginfo("track data read (%dkb)",tracksize*tracknumber*sidenumber/1024); + f=face; + for (t=0;t<tracknumber;t++) { + curtrack=t*sidenumber+f; + + i=(t*sidenumber+f)*tracksize; + if (strncmp((char *)data+i,"Track-Info\r\n",12)) { + rasm_printf(ae,"Invalid track information block side %d track %d",f,t); + FreeAssenv(ae);exit(ABORT_ERROR); + } + sectornumber=data[i+21]; + sectorsize=data[i+20]; + if (sectornumber!=9 || sectorsize!=2) { + rasm_printf(ae,"Cannot read [%s] Invalid DATA format",edskfilename); + FreeAssenv(ae);exit(ABORT_ERROR); + } + memset(checksectorid,0,sizeof(checksectorid)); + /* we want DATA format */ + for (s=0;s<sectornumber;s++) { + if (t!=data[i+24+8*s]) { + rasm_printf(ae,"Invalid track number in sector %02X track %d",data[i+24+8*s+2],t); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (f!=data[i+24+8*s+1]) { + rasm_printf(ae,"Invalid side number in sector %02X track %d",data[i+24+8*s+2],t); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (data[i+24+8*s+2]<0xC1 || data[i+24+8*s+2]>0xC9) { + rasm_printf(ae,"Invalid sector ID in sector %02X track %d",data[i+24+8*s+2],t); + FreeAssenv(ae);exit(ABORT_ERROR); + } else { + checksectorid[data[i+24+8*s+2]-0xC1]=1; + } + if (data[i+24+8*s+3]!=2) { + rasm_printf(ae,"Invalid sector size in sector %02X track %d",data[i+24+8*s+2],t); + FreeAssenv(ae);exit(ABORT_ERROR); + } + } + for (s=0;s<sectornumber;s++) { + if (!checksectorid[s]) { + rasm_printf(ae,"Missing sector %02X track %d",s+0xC1,t); + FreeAssenv(ae);exit(ABORT_ERROR); + } + } + /* piste à piste on lit les blocs DANS L'ORDRE LOGIQUE!!! */ + for (b=0xC1;b<=0xC9;b++) + for (s=0;s<sectornumber;s++) { + if (data[i+24+8*s+2]==b) { + memcpy(&curwrap->blocks[curblock][curoffset],&data[i+0x100+s*512],512); + curoffset+=512; + if (curoffset>=1024) { + curoffset=0; + curblock++; + } + } + } + } + } else if (strncmp((char *)header,"EXTENDED",8)==0) { + rasm_printf(ae,KAYGREEN"updating EDSK [%s] / creator: %-14.14s\n",edskfilename,header+34); + tracknumber=header[34+14]; + sidenumber=header[34+14+1]; + // not in EDSK tracksize=header[34+14+1+1]+header[34+14+1+1+1]*256; +#if TRACE_EDSK + loginfo("tracks: %d sides:%d",tracknumber,sidenumber); +#endif + + if (sidenumber>2) { + rasm_printf(ae,KERROR"[%s] EDSK format is not supported in update mode (ntrack=%d nside=%d)\n",edskfilename,tracknumber,sidenumber); + FreeAssenv(ae);exit(ABORT_ERROR); + } + if (face>=sidenumber) { + rasm_printf(ae,KWARNING"[%s] EDSK has no face %d - DSK updated\n",edskfilename,face); + return; + } + + for (i=disksize=0;i<tracknumber*sidenumber;i++) disksize+=header[0x34+i]*256; +#if TRACE_EDSK + loginfo("total track size: %dkb",disksize/1024); +#endif + + data=MemMalloc(disksize); + memset(data,0,disksize); + if (FileReadBinary(edskfilename,(char *)data,disksize)!=disksize) { + rasm_printf(ae,KERROR"Cannot read DSK tracks!\n"); + FreeAssenv(ae);exit(ABORT_ERROR); + } + + f=face; + for (t=0;t<tracknumber && t<40;t++) { + int track_sectorsize; + + curtrack=t*sidenumber+f; + i=currenttrackposition; + currentsectorposition=i+0x100; + + if (!header[0x34+curtrack] && t<40) { + rasm_printf(ae,KERROR"Unexpected unformated track Side %d Track %02d\n",f,t); + } else { + currenttrackposition+=header[0x34+curtrack]*256; + + if (strncmp((char *)data+i,"Track-Info\r\n",12)) { + rasm_printf(ae,KERROR"Invalid track information block side %d track %d\n",f,t); + FreeAssenv(ae);exit(ABORT_ERROR); + } + sectornumber=data[i+21]; + track_sectorsize=data[i+20]; + if (sectornumber!=9) { + rasm_printf(ae,KERROR"Unsupported track %d (sectornumber=%d sectorsize=%d)\n",t,sectornumber,sectorsize); + FreeAssenv(ae);exit(ABORT_ERROR); + } + memset(checksectorid,0,sizeof(checksectorid)); + /* we want DATA format */ + for (s=0;s<sectornumber;s++) { + sectorid=data[i+24+8*s+2]; + if (sectorid>=0xC1 && sectorid<=0xC9) checksectorid[sectorid-0xC1]=1; else { + rasm_printf(ae,KERROR"invalid sector id %02X for DATA track %d\n",sectorid,t); + return; + } + sectorsize=data[i+24+8*s+3]; + if (sectorsize!=2) { + rasm_printf(ae,KERROR"invalid sector size track %d\n",t); + return; + } + reallength=data[i+24+8*s+6]+data[i+24+8*s+7]*256; /* real length stored */ + if (reallength!=512) { + rasm_printf(ae,KERROR"invalid sector length %d for track %d\n",reallength,t); + return; + } +#if TRACE_EDSK + printf("%02X ",sectorid); +#endif + } + if (track_sectorsize!=2) { + rasm_printf(ae,KWARNING"track %02d has invalid sector size but sectors are OK\n",t); + } +#if TRACE_EDSK + printf("\n"); +#endif + + /* piste à piste on lit les blocs DANS L'ORDRE LOGIQUE!!! */ + for (b=0xC1;b<=0xC9;b++) { + tmpcurrentsectorposition=currentsectorposition; + for (s=0;s<sectornumber;s++) { + if (b==data[i+24+8*s+2]) { + memcpy(&curwrap->blocks[curblock][curoffset],&data[tmpcurrentsectorposition],512); + curoffset+=512; + if (curoffset>=1024) { + curoffset=0; + curblock++; + } + } + reallength=data[i+24+8*s+6]+data[i+24+8*s+7]*256; + tmpcurrentsectorposition+=reallength; + } + } + } + } + + + } else { + rasm_printf(ae,KERROR"file [%s] is not a valid (E)DSK floppy image\n",edskfilename); + FreeAssenv(ae);exit(-923); + } + FileReadBinaryClose(edskfilename); + + /* Rasm management of (e)DSK files is AMSDOS compatible, just need to copy CATalog blocks but sort them... */ + memcpy(&curwrap->entry[0],curwrap->blocks[0],1024); + memcpy(&curwrap->entry[32],curwrap->blocks[1],1024); + /* tri des entrées selon le user */ + qsort(curwrap->entry,64,sizeof(struct s_edsk_wrapper_entry),cmpAmsdosentry); + curwrap->nbentry=64; + for (i=0;i<64;i++) { + if (curwrap->entry[i].user==0xE5) { + curwrap->nbentry=i; + break; + } + } +#if TRACE_EDSK + printf("%d entr%s found\n",curwrap->nbentry,curwrap->nbentry>1?"ies":"y"); + for (i=0;i<curwrap->nbentry;i++) { + printf("[%02d] - ",i); + if (curwrap->entry[i].user<16) { + printf("U%02d [%-8.8s.%c%c%c] %c%c subcpt=#%02X rc=#%02X blocks=",curwrap->entry[i].user,curwrap->entry[i].filename, + curwrap->entry[i].filename[8]&0x7F,curwrap->entry[i].filename[9]&0x7F,curwrap->entry[i].filename[10], + curwrap->entry[i].filename[8]&0x80?'P':'-',curwrap->entry[i].filename[9]&0x80?'H':'-', + curwrap->entry[i].subcpt,curwrap->entry[i].rc); + for (b=0;b<16;b++) if (curwrap->entry[i].blocks[b]) printf("%s%02X",b>0?" ":"",curwrap->entry[i].blocks[b]); else printf("%s ",b>0?" ":""); + if (i&1) printf("\n"); else printf(" | "); + } else { + printf("free entry = rc= blocks= "); + if (i&1) printf("\n"); else printf(" | "); + } + } + if (i&1) printf("\n"); +#endif +} + +struct s_edsk_wrapper *EDSK_select(struct s_assenv *ae,char *edskfilename, int facenumber) +{ + #undef FUNC + #define FUNC "EDSK_select" + + struct s_edsk_wrapper newwrap={0},*curwrap=NULL; + int i; +#if TRACE_EDSK + printf("EDSK_select('%s',%d);\n",edskfilename,facenumber); +#endif + /* check if there is a DSK in memory */ + for (i=0;i<ae->nbedskwrapper;i++) { + if (!strcmp(ae->edsk_wrapper[i].edsk_filename,edskfilename)) { +#if TRACE_EDSK + printf("Found! return %d\n",i); +#endif + return &ae->edsk_wrapper[i]; + } + } + /* not in memory, create an empty struct */ + newwrap.edsk_filename=TxtStrDup(edskfilename); + memset(newwrap.entry,0xE5,sizeof(struct s_edsk_wrapper_entry)*64); + memset(newwrap.blocks[0],0xE5,1024); + memset(newwrap.blocks[1],0xE5,1024); +#if TRACE_EDSK + printf("Not found! create empty struct\n"); +#endif + newwrap.face=facenumber; + ObjectArrayAddDynamicValueConcat((void**)&ae->edsk_wrapper,&ae->nbedskwrapper,&ae->maxedskwrapper,&newwrap,sizeof(struct s_edsk_wrapper)); + /* and load files if the DSK exists on disk */ + curwrap=&ae->edsk_wrapper[ae->nbedskwrapper-1]; + if (FileExists(edskfilename)) { + EDSK_load(ae,curwrap,edskfilename,facenumber); + } + return curwrap; +} + +int EDSK_addfile(struct s_assenv *ae,char *edskfilename,int facenumber, char *filename,unsigned char *indata,int insize, int offset, int run) +{ + #undef FUNC + #define FUNC "EDSK_addfile" + + struct s_edsk_wrapper *curwrap=NULL; + char amsdos_name[12]={0}; + int j,i,ia,ib,ie,filesize,idxdata; + int fb[180],rc,idxb; + unsigned char *data=NULL; + int size=0; + int firstblock; + + curwrap=EDSK_select(ae,edskfilename,facenumber); + /* update struct */ + size=insize+128; + data=MemMalloc(size); + strcpy(amsdos_name,MakeAMSDOS_name(ae,filename)); + memcpy(data,MakeAMSDOSHeader(run,offset,offset+insize,amsdos_name),128); + memcpy(data+128,indata,insize); + /* overwrite check */ +#if TRACE_EDSK + printf("EDSK_addfile will checks %d entr%s for [%s]\n",curwrap->nbentry,curwrap->nbentry>1?"ies":"y",amsdos_name); +#endif + for (i=0;i<curwrap->nbentry;i++) { + if (!strncmp((char *)curwrap->entry[i].filename,amsdos_name,11)) { + if (!ae->edskoverwrite) { + MakeError(ae,NULL,0,"Error - Cannot save [%s] in edsk [%s] with overwrite disabled as the file already exists\n",amsdos_name,edskfilename); + MemFree(data); + return 0; + } else { + /* overwriting previous file */ +#if TRACE_EDSK + printf(" -> reset previous entry %d with 0xE5\n",i); +#endif + memset(&curwrap->entry[i],0xE5,sizeof(struct s_edsk_wrapper_entry)); + } + } + } + /* find free blocks */ +#if TRACE_EDSK + printf("EDSK_addfile find free blocks\n"); +#endif + fb[0]=fb[1]=0; + for (i=2;i<180;i++) fb[i]=1; + for (i=0;i<curwrap->nbentry;i++) { + if (curwrap->entry[i].rc!=0xE5 && curwrap->entry[i].rc!=0) { + /* entry found, compute number of blocks to read */ + rc=curwrap->entry[i].rc/8; + if (curwrap->entry[i].rc%8) rc++; /* adjust value */ + /* mark as used */ + for (j=0;j<rc;j++) { + fb[curwrap->entry[i].blocks[j]]=0; + } + } + } + /* set directory, blocks and data in blocks */ + firstblock=-1; + filesize=size; + idxdata=0; + ia=0; + +#if TRACE_EDSK + printf("Writing [%s] size=%d\n",amsdos_name,size); +#endif + + while (filesize>0) { + if (filesize>16384) { + /* extended entry */ +#if TRACE_EDSK + printf("extended entry for file (filesize=%d)\nblocklist: ",filesize); +#endif + if ((ie=EDSK_getdirid(curwrap))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DIRECTORY FULL\n",edskfilename); + MemFree(data); + return 0; + } + if (curwrap->nbentry<=ie) curwrap->nbentry=ie+1; + idxb=0; + for (i=0;i<16;i++) { + if ((ib=EDSK_getblockid(fb))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DISK FULL\n",edskfilename); + MemFree(data); + return 0; + } else { + if (firstblock==-1) firstblock=ib; + +#if TRACE_EDSK + printf("%02X ",ib); +#endif + memcpy(curwrap->blocks[ib],data+idxdata,1024); + idxdata+=1024; + filesize-=1024; + fb[ib]=0; + curwrap->entry[ie].blocks[idxb++]=ib; + } + } +#if TRACE_EDSK + printf("\n"); +#endif + memcpy(curwrap->entry[ie].filename,amsdos_name,11); + curwrap->entry[ie].subcpt=ia; + curwrap->entry[ie].rc=0x80; + curwrap->entry[ie].user=0; + ia++; + idxb=0; + } else { + /* last entry */ +#if TRACE_EDSK + printf("last entry for file (filesize=%d)\nblocklist: ",filesize); +#endif + if ((ie=EDSK_getdirid(curwrap))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DIRECTORY FULL\n",edskfilename); + MemFree(data); + return 0; + } + if (curwrap->nbentry<=ie) curwrap->nbentry=ie+1; + /* calcul du nombre de sous blocs de 128 octets */ + curwrap->entry[ie].rc=filesize/128; + if (filesize%128) { + curwrap->entry[ie].rc+=1; + } + idxb=0; + for (i=0;i<16 && filesize>0;i++) { + if ((ib=EDSK_getblockid(fb))==-1) { + MakeError(ae,NULL,0,"Error - edsk [%s] DISK FULL\n",edskfilename); + MemFree(data); + return 0; + } else { + if (firstblock==-1) firstblock=ib; +#if TRACE_EDSK + printf("%02X ",ib); +#endif + + memcpy(curwrap->blocks[ib],&data[idxdata],filesize>1024?1024:filesize); + idxdata+=1024; + filesize-=1024; + fb[ib]=0; + curwrap->entry[ie].blocks[idxb++]=ib; + } + } +#if TRACE_EDSK + printf("\n"); +#endif + filesize=0; + memcpy(curwrap->entry[ie].filename,amsdos_name,11); + curwrap->entry[ie].subcpt=ia; + curwrap->entry[ie].user=0; + } + } + + MemFree(data); + return 1; +} + +void EDSK_build_amsdos_directory(struct s_edsk_wrapper *face) +{ + #undef FUNC + #define FUNC "EDSK_build_amsdos_directory" + + unsigned char amsdosdir[2048]={0}; + int i,idx=0,b; + + if (!face) return; + +#if TRACE_EDSK +printf("build amsdos dir with %d entries\n",face->nbentry); +#endif + for (i=0;i<face->nbentry;i++) { + if (face->entry[i].rc && face->entry[i].rc!=0xE5) { + amsdosdir[idx]=face->entry[i].user; + memcpy(amsdosdir+idx+1,face->entry[i].filename,11); + amsdosdir[idx+12]=face->entry[i].subcpt; + amsdosdir[idx+13]=0; + amsdosdir[idx+14]=0; + amsdosdir[idx+15]=face->entry[i].rc; +#if TRACE_EDSK +printf("%-11.11s [%02X.%02X] blocks:",amsdosdir+idx+1,amsdosdir[idx+12],amsdosdir[idx+15]); +#endif + for (b=0;b<16;b++) { + if (face->entry[i].blocks[b]!=0xE5) { + amsdosdir[idx+16+b]=face->entry[i].blocks[b]; +#if TRACE_EDSK + printf("%s%02X",b>0?".":"",amsdosdir[idx+16+b]); +#endif + } else { + amsdosdir[idx+16+b]=0; + } + } +#if TRACE_EDSK +printf("\n"); +#endif + } + idx+=32; + } +#if TRACE_EDSK +printf("filling amsdos remaining entries (%d) with #E5\n",64-face->nbentry); +#endif + memset(amsdosdir+idx,0xE5,32*(64-face->nbentry)); + + /* AMSDOS directory copy to blocks! */ + memcpy(face->blocks[0],amsdosdir,1024); + memcpy(face->blocks[1],amsdosdir+1024,1024); +} +void EDSK_write_file(struct s_assenv *ae,struct s_edsk_wrapper *faceA,struct s_edsk_wrapper *faceB) +{ + #undef FUNC + #define FUNC "EDSK_write_file" + + struct s_edsk_wrapper emptyface={0}; + unsigned char header[256]={0}; + unsigned char trackblock[256]={0}; + int idblock,blockoffset; + int i,t; + + if (!faceA && !faceB) return; + + /* création des deux blocs du directory par face */ + EDSK_build_amsdos_directory(faceA); + EDSK_build_amsdos_directory(faceB); + /* écriture header */ + strcpy((char *)header,"EXTENDED CPC DSK File\r\nDisk-Info\r\n"); + strcpy((char *)header+0x22,RASM_SNAP_VERSION); + header[0x30]=40; + if (!faceA) { + faceA=&emptyface; + faceA->edsk_filename=TxtStrDup(faceB->edsk_filename); + } +#if TRACE_EDSK + printf("deleting [%s]\n",faceA->edsk_filename); +#endif + FileRemoveIfExists(faceA->edsk_filename); + + if (faceB!=NULL) header[0x31]=2; else header[0x31]=1; + for (i=0;i<header[0x30]*header[0x31];i++) header[0x34+i]=19; /* tracksize=(9*512+256)/256 */ +#if TRACE_EDSK + printf("writing EDSK header (256b)\n"); +#endif + FileWriteBinary(faceA->edsk_filename,(char *)header,256); + + /* écriture des pistes */ + for (t=0;t<40;t++) { + strcpy((char *)trackblock,"Track-Info\r\n"); + trackblock[0x10]=t; + trackblock[0x11]=0; + trackblock[0x14]=2; + trackblock[0x15]=9; + trackblock[0x16]=0x4E; + trackblock[0x17]=0xE5; + i=0; + while (1) { + trackblock[0x18+i*8+0]=trackblock[0x10]; + trackblock[0x18+i*8+1]=trackblock[0x11]; + trackblock[0x18+i*8+2]=(i>>1)+0xC1; +#if TRACE_EDSK + if (t<3) printf("%02X ",trackblock[0x18+i*8+2]); +#endif + trackblock[0x18+i*8+3]=2; + trackblock[0x18+i*8+4]=0; + trackblock[0x18+i*8+5]=0; + trackblock[0x18+i*8+6]=0; + trackblock[0x18+i*8+7]=2; + i++; + if (i==9) break; + /* interleave */ + trackblock[0x18+i*8+0]=trackblock[0x10]; + trackblock[0x18+i*8+1]=trackblock[0x11]; + trackblock[0x18+i*8+2]=(i>>1)+0xC6; /* start at C6 */ +#if TRACE_EDSK + if (t<3) printf("%02X ",trackblock[0x18+i*8+2]); +#endif + trackblock[0x18+i*8+3]=2; + trackblock[0x18+i*8+4]=0; + trackblock[0x18+i*8+5]=0; + trackblock[0x18+i*8+6]=0; + trackblock[0x18+i*8+7]=2; + i++; + } +#if TRACE_EDSK + if (t<3) printf("\n"); else if (t==3) printf("...\n"); +#endif + /* écriture du track info */ + FileWriteBinary(faceA->edsk_filename,(char *)trackblock,256); + + + /* il faut convertir les blocs logiques en secteurs physiques ET entrelacés */ + idblock=t*9/2; + blockoffset=((t*9)%2)*512; + + /* le premier secteur de la piste est à cheval sur le bloc logique une fois sur deux */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock][0]+blockoffset,512); /* C1 */ + if (!blockoffset) { + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+512,512); /* C6 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+0][0]+512,512); /* C2 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+0,512); /* C7 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+0,512); /* C3 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+512,512); /* C8 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+512,512); /* C4 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+0,512); /* C9 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+0,512); /* C5 */ + } else { + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+0,512); /* C6 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+0,512); /* C2 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+3][0]+512,512); /* C7 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+1][0]+512,512); /* C3 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+0,512); /* C8 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+0,512); /* C4 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+4][0]+512,512); /* C9 */ + FileWriteBinary(faceA->edsk_filename,(char *)&faceA->blocks[idblock+2][0]+512,512); /* C5 */ + } + + /* @@TODO ça semble un peu foireux comme procédé */ + if (faceB) { +#if TRACE_EDSK + printf("writing EDSK face B /!\\ probably NOT WORKING !!!\n"); +#endif + trackblock[0x11]=1; + for (i=0;i<9;i++) { + trackblock[0x18+i*8+0]=trackblock[0x10]; + trackblock[0x18+i*8+1]=trackblock[0x11]; + } + /* écriture du track info */ + FileWriteBinary(faceB->edsk_filename,(char *)trackblock,256); + /* écriture des secteurs */ + idblock=t*9/2; + blockoffset=((t*9)%2)*512; + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock][0]+blockoffset,512); + if (!blockoffset) { + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+512,512); /* C6 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+0][0]+512,512); /* C2 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+0,512); /* C7 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+0,512); /* C3 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+512,512); /* C8 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+512,512); /* C4 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+0,512); /* C9 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+0,512); /* C5 */ + } else { + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+0,512); /* C6 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+0,512); /* C2 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+3][0]+512,512); /* C7 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+1][0]+512,512); /* C3 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+0,512); /* C8 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+0,512); /* C4 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+4][0]+512,512); /* C9 */ + FileWriteBinary(faceB->edsk_filename,(char *)&faceB->blocks[idblock+2][0]+512,512); /* C5 */ + } + } + } + FileWriteBinaryClose(faceA->edsk_filename); + rasm_printf(ae,KIO"Write edsk file %s\n",faceA->edsk_filename); +} +void EDSK_write(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "EDSK_write" + + struct s_edsk_wrapper *faceA,*faceB; + char *edskfilename; + int i,j; + + /* on passe en revue toutes les structs */ + for (i=0;i<ae->nbedskwrapper;i++) { + /* already done */ + if (ae->edsk_wrapper[i].face==-1) continue; + + switch (ae->edsk_wrapper[i].face) { + default: + case 0:faceA=&ae->edsk_wrapper[i];faceB=NULL;break; + case 1:faceA=NULL;faceB=&ae->edsk_wrapper[i];break; + } + /* doit-on fusionner avec une autre face? */ + for (j=i+1;j<ae->nbedskwrapper;j++) { + if (!strcmp(ae->edsk_wrapper[i].edsk_filename,ae->edsk_wrapper[j].edsk_filename)) { + /* found another face for the floppy */ + switch (ae->edsk_wrapper[j].face) { + default: + case 0:faceA=&ae->edsk_wrapper[j];break; + case 1:faceB=&ae->edsk_wrapper[j];break; + } + } + } + EDSK_write_file(ae,faceA,faceB); + } +} +void PopAllSave(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "PopAllSave" + + unsigned char *AmsdosHeader; + char *dskfilename; + char *filename; + int offset,size,run; + int i,is,erreur=0; + + for (is=0;is<ae->nbsave;is++) { + /* avoid quotes */ + filename=ae->wl[ae->save[is].iw].w; + filename[strlen(filename)-1]=0; + filename++; + /**/ + +#if TRACE_EDSK + printf("woff=[%s](%d) wsize=[%s](%d)\n",ae->wl[ae->save[is].ioffset].w,ae->save[is].ioffset,ae->wl[ae->save[is].isize].w,ae->save[is].isize); +#endif + + ae->idx=ae->save[is].ioffset; /* exp hack */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + offset=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + + ae->idx=ae->save[is].isize; /* exp hack */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + size=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + + ae->idx=ae->save[is].irun; /* exp hack */ + if (ae->idx) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + run=RoundComputeExpression(ae,ae->wl[ae->idx].w,0,0,0); + } else { + run=offset; + } + + if (size<1 || size>65536) { + MakeError(ae,NULL,0,"cannot save [%s] as the size is invalid!\n",filename); + continue; + } + if (offset<0 || offset>65535) { + MakeError(ae,NULL,0,"cannot save [%s] as the offset is invalid!\n",filename); + continue; + } + if (offset+size>65536) { + MakeError(ae,NULL,0,"cannot save [%s] as the offset+size will be out of bounds!\n",filename); + continue; + } + /* DSK management */ + if (ae->save[is].dsk) { + if (ae->save[is].iwdskname!=-1) { + /* obligé de dupliquer à cause du reuse */ + dskfilename=TxtStrDup(ae->wl[ae->save[is].iwdskname].w); + dskfilename[strlen(dskfilename)-1]=0; + if (!EDSK_addfile(ae,dskfilename+1,ae->save[is].face,filename,ae->mem[ae->save[is].ibank]+offset,size,offset,run)) { + erreur++; + break; + } + MemFree(dskfilename); + } + } else if (ae->save[is].tape) { + char TZX_header[10]; + unsigned char IDval[2]; + int wrksize,nbblock; + + /* output file on filesystem */ + FileRemoveIfExists(filename); + + strcpy(TZX_header,"ZXTape!"); + TZX_header[7]=0x1A; + TZX_header[8]=1; + TZX_header[9]=20; + FileWriteBinary(filename,(char *)TZX_header,10); + + IDval[0]=0x20; + FileWriteBinary(filename,(char *)IDval,1); + IDval[0]=0x03; + IDval[1]=0x03; + FileWriteBinary(filename,(char *)IDval,2); // first silence + + IDval[0]=0x10; + FileWriteBinary(filename,(char *)IDval,1); + IDval[0]=0x03; + IDval[1]=0x03; + FileWriteBinary(filename,(char *)IDval,2); // little silence + if (size+128<=2048) wrksize=size+128; else wrksize=2048; + IDval[0]=(wrksize+128) & 0xFF; + IDval[1]=((wrksize+128)>>8) & 0xFF; + FileWriteBinary(filename,(char *)IDval,2); // block len + nbblock=1; + AmsdosHeader=MakeAMSDOSHeader(run,offset,offset+size,MakeAMSDOS_name(ae,filename)); + FileWriteBinary(filename,(char *)AmsdosHeader,128); + if (size<=2048-128) { + FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,size); + } else { + FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,2048-128); + size=size-2048+128; + while (size>0) { + nbblock++; + /* additionnal block */ + IDval[0]=0x10; + FileWriteBinary(filename,(char *)IDval,1); + IDval[0]=0x04; + IDval[1]=0x04; + FileWriteBinary(filename,(char *)IDval,2); // silence 1s delay + if (size<=2048) wrksize=size; else wrksize=2048; + IDval[0]=(wrksize+128) & 0xFF; + IDval[1]=((wrksize+128)>>8) & 0xFF; + FileWriteBinary(filename,(char *)IDval,2); // block len + FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,wrksize); + /* adjust */ + size=size-2048; + } + } + FileWriteBinaryClose(filename); + rasm_printf(ae,KIO"Write tape file %s (%d block%s)\n",filename,nbblock,nbblock>1?"s":""); + } else { + /* output file on filesystem */ + rasm_printf(ae,KIO"Write binary file %s (%d byte%s)\n",filename,size,size>1?"s":""); + FileRemoveIfExists(filename); + if (ae->save[is].amsdos) { + AmsdosHeader=MakeAMSDOSHeader(run,offset,offset+size,MakeAMSDOS_name(ae,filename)); + FileWriteBinary(filename,(char *)AmsdosHeader,128); + } + FileWriteBinary(filename,(char*)ae->mem[ae->save[is].ibank]+offset,size); + FileWriteBinaryClose(filename); + } + } + if (!erreur) EDSK_write(ae); + + for (i=0;i<ae->nbedskwrapper;i++) { + MemFree(ae->edsk_wrapper[i].edsk_filename); + } + if (ae->maxedskwrapper) MemFree(ae->edsk_wrapper); + + if (ae->nbsave) { + MemFree(ae->save); + } +} + +void PopAllExpression(struct s_assenv *ae, int crunched_zone) +{ + #undef FUNC + #define FUNC "PopAllExpression" + + static int first=1; + double v; + long r; + int i; + unsigned char *mem; + char *expr; + + /* pop all expressions BUT thoses who where already computed (in crunched blocks) */ + + /* calcul des labels et expressions en zone crunch (et locale?) + les labels doivent pointer: + - une valeur absolue (numerique ou variable calculee) -> completement transparent + - un label dans la meme zone de crunch -> label->lz=1 && verif de la zone crunch + - un label hors zone crunch MAIS avant toute zone de crunch de la bank destination (!label->lz) + + idealement on doit tolerer les adresses situees apres le crunch dans une autre ORG zone! + + on utilise ae->stage pour créer un état intermédiaire dans le ComputeExpressionCore + */ + if (crunched_zone>=0) { + ae->stage=1; + } else { + /* on rescanne tout pour combler les trous */ + ae->stage=2; + first=1; + } + + for (i=first;i<ae->ie;i++) { + /* first compute only crunched expression (0,1,2,3,...) then (-1) at the end */ + if (crunched_zone>=0) { + /* calcul des expressions en zone crunch */ + if (ae->expression[i].lz<crunched_zone) continue; + if (ae->expression[i].lz>crunched_zone) { + first=i; + break; + } + } else { + if (ae->expression[i].lz>=0) continue; + } + + mem=ae->mem[ae->expression[i].ibank]; + + if (ae->expression[i].reference) { + expr=ae->expression[i].reference; + } else { + expr=ae->wl[ae->expression[i].iw].w; + } + v=ComputeExpressionCore(ae,expr,ae->expression[i].ptr,i); + r=(long)floor(v+ae->rough); + switch (ae->expression[i].zetype) { + case E_EXPRESSION_J8: + r=r-ae->expression[i].ptr-2; + if (r<-128 || r>127) { + MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"relative offset %d too far [%s]\n",r,ae->wl[ae->expression[i].iw].w); + } + mem[ae->expression[i].wptr]=(unsigned char)r; + break; + case E_EXPRESSION_IV81: + /* for enhanced 16bits instructions */ + r++; + case E_EXPRESSION_0V8: + case E_EXPRESSION_IV8: + case E_EXPRESSION_3V8: + case E_EXPRESSION_V8: + if (r>255 || r<-128) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value #%X to #%X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFF); + } + mem[ae->expression[i].wptr]=(unsigned char)r; + break; + case E_EXPRESSION_IV16: + case E_EXPRESSION_V16: + case E_EXPRESSION_V16C: + case E_EXPRESSION_0V16: + if (r>65535 || r<-32768) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value #%X to #%X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + } + mem[ae->expression[i].wptr]=(unsigned char)r&0xFF; + mem[ae->expression[i].wptr+1]=(unsigned char)((r&0xFF00)>>8); + break; + case E_EXPRESSION_0V32: + /* meaningless in 32 bits architecture... */ + if (v>4294967295 || v<-2147483648) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: truncating value\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l); + } + mem[ae->expression[i].wptr]=(unsigned char)r&0xFF; + mem[ae->expression[i].wptr+1]=(unsigned char)((r>>8)&0xFF); + mem[ae->expression[i].wptr+2]=(unsigned char)((r>>16)&0xFF); + mem[ae->expression[i].wptr+3]=(unsigned char)((r>>24)&0xFF); + break; + case E_EXPRESSION_0VR: + /* convert v double value to Amstrad REAL */ + memcpy(&mem[ae->expression[i].wptr],__internal_MakeAmsdosREAL(ae,v,i),5); + break; + case E_EXPRESSION_IM: + switch (r) { + case 0x00:mem[ae->expression[i].wptr]=0x46;break; + case 0x01:mem[ae->expression[i].wptr]=0x56;break; + case 0x02:mem[ae->expression[i].wptr]=0x5E;break; + default: + MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"IM 0,1 or 2 only\n"); + mem[ae->expression[i].wptr]=0; + } + break; + case E_EXPRESSION_RST: + switch (r) { + case 0x00:mem[ae->expression[i].wptr]=0xC7;break; + case 0x08:mem[ae->expression[i].wptr]=0xCF;break; + case 0x10:mem[ae->expression[i].wptr]=0xD7;break; + case 0x18:mem[ae->expression[i].wptr]=0xDF;break; + case 0x20:mem[ae->expression[i].wptr]=0xE7;break; + case 0x28:mem[ae->expression[i].wptr]=0xEF;break; + case 0x30:mem[ae->expression[i].wptr]=0xF7;break; + case 0x38:mem[ae->expression[i].wptr]=0xFF;break; + default: + MakeError(ae,GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,"RST #0,#8,#10,#18,#20,#28,#30,#38 only\n"); + mem[ae->expression[i].wptr]=0; + } + break; + case E_EXPRESSION_RUN: + if (r<0 || r>65535) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: run adress truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + } + ae->snapshot.registers.LPC=r&0xFF; + ae->snapshot.registers.HPC=(r>>8)&0xFF; + break; + case E_EXPRESSION_ZXRUN: + if (r<0 || r>65535) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: run adress truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + } + ae->zxsnapshot.run=r&0xFFFF; + break; + case E_EXPRESSION_ZXSTACK: + if (r<0 || r>65535) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: stack adress truncated from %X to %X\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l,r,r&0xFFFF); + } + ae->zxsnapshot.stack=r&0xFFFF; + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - unknown expression type\n",GetExpFile(ae,i),ae->wl[ae->expression[i].iw].l); + FreeAssenv(ae);exit(-8); + } + } +} + +void InsertLabelToTree(struct s_assenv *ae, struct s_label *label) +{ + #undef FUNC + #define FUNC "InsertLabelToTree" + + struct s_crclabel_tree *curlabeltree; + int radix,dek=32; + + curlabeltree=&ae->labeltree; + while (dek) { + dek=dek-8; + radix=(label->crc>>dek)&0xFF; + if (curlabeltree->radix[radix]) { + curlabeltree=curlabeltree->radix[radix]; + } else { + curlabeltree->radix[radix]=MemMalloc(sizeof(struct s_crclabel_tree)); + curlabeltree=curlabeltree->radix[radix]; + memset(curlabeltree,0,sizeof(struct s_crclabel_tree)); + } + } + ObjectArrayAddDynamicValueConcat((void**)&curlabeltree->label,&curlabeltree->nlabel,&curlabeltree->mlabel,&label[0],sizeof(struct s_label)); +} + +/* use by structure mechanism and label import to add fake labels */ +void PushLabelLight(struct s_assenv *ae, struct s_label *curlabel) { + #undef FUNC + #define FUNC "PushLabelLight" + + struct s_label *searched_label; + + /* PushLabel light */ + if ((searched_label=SearchLabel(ae,curlabel->name,curlabel->crc))!=NULL) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"%s caused duplicate label [%s]\n",ae->idx?"Structure insertion":"Label import",curlabel->name); + MemFree(curlabel->name); + } else { + curlabel->backidx=ae->il; + ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,curlabel,sizeof(struct s_label)); + InsertLabelToTree(ae,curlabel); + } +} +void PushLabel(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "PushLabel" + + struct s_label curlabel={0},*searched_label; + char *curlabelname; + int i; + /* label with counters */ + struct s_expr_dico *curdic; + char curval[32]; + char *varbuffer,*expr; + char *starttag,*endtag,*tagcheck; + int taglen,tagidx,lenw,tagcount=0; + int crc,newlen,touched; + + if (ae->AutomateValidLabelFirst[ae->wl[ae->idx].w[0]]) { + for (i=1;ae->wl[ae->idx].w[i];i++) { + if (ae->wl[ae->idx].w[i]=='{') tagcount++; else if (ae->wl[ae->idx].w[i]=='}') tagcount--; + if (!tagcount) { + if (!ae->AutomateValidLabel[ae->wl[ae->idx].w[i]]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid char in label declaration (%c)\n",ae->wl[ae->idx].w[i]); + return; + } + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid first char in label declaration (%c)\n",ae->wl[ae->idx].w[0]); + return; + } + + switch (i) { + case 1: + switch (ae->wl[ae->idx].w[0]) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'H': + case 'L': + case 'I': + case 'R': + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + default:break; + } + break; + case 2: + if (strcmp(ae->wl[ae->idx].w,"AF")==0 || strcmp(ae->wl[ae->idx].w,"BC")==0 || strcmp(ae->wl[ae->idx].w,"DE")==0 || strcmp(ae->wl[ae->idx].w,"HL")==0 || + strcmp(ae->wl[ae->idx].w,"IX")==0 || strcmp(ae->wl[ae->idx].w,"IY")==0 || strcmp(ae->wl[ae->idx].w,"SP")==0 || + strcmp(ae->wl[ae->idx].w,"LX")==0 || strcmp(ae->wl[ae->idx].w,"HX")==0 || strcmp(ae->wl[ae->idx].w,"XL")==0 || strcmp(ae->wl[ae->idx].w,"XH")==0 || + strcmp(ae->wl[ae->idx].w,"LY")==0 || strcmp(ae->wl[ae->idx].w,"HY")==0 || strcmp(ae->wl[ae->idx].w,"YL")==0 || strcmp(ae->wl[ae->idx].w,"YH")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + } + break; + case 3: + if (strcmp(ae->wl[ae->idx].w,"IXL")==0 || strcmp(ae->wl[ae->idx].w,"IYL")==0 || strcmp(ae->wl[ae->idx].w,"IXH")==0 || strcmp(ae->wl[ae->idx].w,"IYH")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + } + break; + case 4: + if (strcmp(ae->wl[ae->idx].w,"VOID")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use reserved word [%s] for label\n",ae->wl[ae->idx].w); + return; + } + default:break; + } + + /******************************************************* + v a r i a b l e s i n l a b e l n a m e + *******************************************************/ + varbuffer=TranslateTag(ae,TxtStrDup(ae->wl[ae->idx].w),&touched,1,E_TAGOPTION_NONE); + + /************************************************** + s t r u c t u r e d e c l a r a t i o n + **************************************************/ + if (ae->getstruct) { + struct s_rasmstructfield rasmstructfield={0}; + if (varbuffer[0]=='@') { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Please no local label in a struct [%s]\n",ae->wl[ae->idx].w); + return; + } + /* copy label+offset in the structure */ + rasmstructfield.name=TxtStrDup(varbuffer); + rasmstructfield.offset=ae->codeadr; + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, + &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, + &rasmstructfield,sizeof(rasmstructfield)); + /* label is structname+field */ + curlabelname=curlabel.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+strlen(varbuffer)+2); + sprintf(curlabel.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,varbuffer); + curlabel.iw=-1; + /* legacy */ + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=ae->codeadr; +#if TRACE_STRUCT + printf("pushLabel (struct) [%X] [%s]\n",curlabel.ptr,curlabel.name); +#endif + } else { + /************************************************** + l a b e l s + **************************************************/ + /* labels locaux */ + if (varbuffer[0]=='@' && (ae->ir || ae->iw || ae->imacro)) { + curlabel.iw=-1; + curlabel.local=1; + curlabelname=curlabel.name=MakeLocalLabel(ae,varbuffer,NULL); + curlabel.crc=GetCRC(curlabel.name); + + /* local labels ALSO set new reference */ + if (ae->lastglobalalloc) { +//printf("push LOCAL is freeing lastgloballabel\n"); + MemFree(ae->lastgloballabel); + } + ae->lastgloballabel=TxtStrDup(curlabelname); +//printf("push LOCAL as reference for proximity label -> [%s]\n",ae->lastgloballabel); + ae->lastgloballabellen=strlen(ae->lastgloballabel); + ae->lastglobalalloc=1; + } else { + switch (varbuffer[0]) { + case '.': + if (ae->dams) { + /* old Dams style declaration (remove the dot) */ + i=0; + do { + varbuffer[i]=varbuffer[i+1]; + ae->wl[ae->idx].w[i]=ae->wl[ae->idx].w[i+1]; + i++; + } while (varbuffer[i]!=0); + if (!touched) { + curlabel.iw=ae->idx; + } else { + curlabel.iw=-1; + curlabel.name=varbuffer; + } + curlabel.crc=GetCRC(varbuffer); + curlabelname=varbuffer; + } else { + /* proximity labels */ + if (ae->lastgloballabel) { + curlabelname=MemMalloc(strlen(varbuffer)+1+ae->lastgloballabellen); + sprintf(curlabelname,"%s%s",ae->lastgloballabel,varbuffer); + MemFree(varbuffer); + touched=1; // cause realloc! + curlabel.iw=-1; + curlabel.name=varbuffer=curlabelname; + curlabel.crc=GetCRC(varbuffer); +//printf("push proximity label that may be exported [%s]->[%s]\n",ae->wl[ae->idx].w,varbuffer); + } else { + /* MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create proximity label [%s] as there is no previous global label\n",varbuffer); + return; */ + + // not optimal but! + curlabelname=TxtStrDup(varbuffer); + MemFree(varbuffer); + touched=1; // cause realloc! + curlabel.iw=-1; + curlabel.name=varbuffer=curlabelname; + curlabel.crc=GetCRC(varbuffer); + } + } + break; + default: + if (!touched) { + curlabel.iw=ae->idx; + } else { + curlabel.iw=-1; + curlabel.name=varbuffer; + } + curlabel.crc=GetCRC(varbuffer); + curlabelname=varbuffer; + /* global labels set new reference */ + if (ae->lastglobalalloc) MemFree(ae->lastgloballabel); + ae->lastgloballabel=ae->wl[ae->idx].w; + ae->lastsuperglobal=ae->wl[ae->idx].w; + ae->lastgloballabellen=strlen(ae->wl[ae->idx].w); + ae->lastglobalalloc=0; +//printf("SET global label [%s] l=%d\n",ae->lastgloballabel,ae->lastgloballabellen); + break; + } + + /* contrôle dico uniquement avec des labels non locaux */ + if (SearchDico(ae,curlabelname,curlabel.crc)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create label [%s] as there is already a variable with the same name\n",curlabelname); + return; + } + if(SearchAlias(ae,curlabel.crc,curlabelname)!=-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot create label [%s] as there is already an alias with the same name\n",curlabelname); + return; + } + } + curlabel.ptr=ae->codeadr; + curlabel.ibank=ae->activebank; + curlabel.iorgzone=ae->io-1; + curlabel.lz=ae->lz; + } + + if ((searched_label=SearchLabel(ae,curlabelname,curlabel.crc))!=NULL) { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Duplicate label [%s] - previously defined in [%s:%d]\n",curlabelname,ae->filename[searched_label->fileidx],searched_label->fileline); + if (curlabel.iw==-1) MemFree(curlabelname); + } else { +//printf("PushLabel(%s) name=%s crc=%X\n",curlabelname,curlabel.name?curlabel.name:"null",curlabel.crc); + curlabel.fileidx=ae->wl[ae->idx].ifile; + curlabel.fileline=ae->wl[ae->idx].l; + curlabel.autorise_export=ae->autorise_export; + curlabel.backidx=ae->il; + ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); + InsertLabelToTree(ae,&curlabel); + } + + if (!touched) MemFree(varbuffer); +} + + +unsigned char *EncodeSnapshotRLE(unsigned char *memin, int *lenout) { + #undef FUNC + #define FUNC "EncodeSnapshotRLE" + + int i,cpt,idx=0; + unsigned char *memout=NULL; + + memout=MemMalloc(65540); + + for (i=0;i<65536;) { + for (cpt=1;cpt<255;cpt++) if (memin[i]!=memin[i+cpt]) break; + if (cpt>=3 || memin[i]==0xE5) { + memout[idx++]=0xE5; + memout[idx++]=cpt; + memout[idx++]=memin[i]; + i+=cpt; + } else { + memout[idx++]=memin[i++]; + } + } + if (lenout) *lenout=idx; + if (idx<65536) return memout; + + MemFree(memout); + return NULL; +} + + + +#undef FUNC +#define FUNC "Instruction CORE" + +void _IN(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (strcmp(ae->wl[ae->idx+2].w,"(C)")==0) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_0: + case CRC_F:___output(ae,0xED);___output(ae,0x70);ae->nop+=4;break; + case CRC_A:___output(ae,0xED);___output(ae,0x78);ae->nop+=3;break; + case CRC_B:___output(ae,0xED);___output(ae,0x40);ae->nop+=4;break; + case CRC_C:___output(ae,0xED);___output(ae,0x48);ae->nop+=4;break; + case CRC_D:___output(ae,0xED);___output(ae,0x50);ae->nop+=4;break; + case CRC_E:___output(ae,0xED);___output(ae,0x58);ae->nop+=4;break; + case CRC_H:___output(ae,0xED);___output(ae,0x60);ae->nop+=4;break; + case CRC_L:___output(ae,0xED);___output(ae,0x68);ae->nop+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is IN [0,F,A,B,C,D,E,H,L],(C)\n"); + } + } else if (strcmp(ae->wl[ae->idx+1].w,"A")==0 && StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xDB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IN [0,F,A,B,C,D,E,H,L],(C) or IN A,(n) only\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IN [0,F,A,B,C,D,E,H,L],(C) or IN A,(n) only\n"); + } +} + +void _OUT(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (strcmp(ae->wl[ae->idx+1].w,"(C)")==0) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_0:___output(ae,0xED);___output(ae,0x71);ae->nop+=4;break; + case CRC_A:___output(ae,0xED);___output(ae,0x79);ae->nop+=4;break; + case CRC_B:___output(ae,0xED);___output(ae,0x41);ae->nop+=4;break; + case CRC_C:___output(ae,0xED);___output(ae,0x49);ae->nop+=4;break; + case CRC_D:___output(ae,0xED);___output(ae,0x51);ae->nop+=4;break; + case CRC_E:___output(ae,0xED);___output(ae,0x59);ae->nop+=4;break; + case CRC_H:___output(ae,0xED);___output(ae,0x61);ae->nop+=4;break; + case CRC_L:___output(ae,0xED);___output(ae,0x69);ae->nop+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is OUT (C),[0,A,B,C,D,E,H,L]\n"); + } + } else if (strcmp(ae->wl[ae->idx+2].w,"A")==0 && StringIsMem(ae->wl[ae->idx+1].w)) { + ___output(ae,0xD3); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUT (C),[0,A,B,C,D,E,H,L] or OUT (n),A only\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUT (C),[0,A,B,C,D,E,H,L] or OUT (n),A only\n"); + } +} + +void _EX(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_DE:___output(ae,0xEB);ae->nop+=1;break; + case CRC_MSP:___output(ae,0xE3);ae->nop+=6;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX HL,[(SP),DE]\n"); + } + break; + case CRC_AF: + if (strcmp(ae->wl[ae->idx+2].w,"AF'")==0) { + ___output(ae,0x08);ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX AF,AF'\n"); + } + break; + case CRC_MSP: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_HL:___output(ae,0xE3);ae->nop+=6;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xE3);ae->nop+=7;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xE3);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX (SP),[HL,IX,IY]\n"); + } + break; + case CRC_DE: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_HL:___output(ae,0xEB);ae->nop+=1;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX DE,HL\n"); + } + break; + case CRC_IX: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_MSP:___output(ae,0xDD);___output(ae,0xE3);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX IX,(SP)\n"); + } + break; + case CRC_IY: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_MSP:___output(ae,0xFD);___output(ae,0xE3);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX IY,(SP)\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is EX [AF,DE,HL,(SP),IX,IY],reg16\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use EX reg16,reg16\n"); + } +} + +void _SBC(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* do implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x9F);ae->nop+=1;break; + case CRC_MHL:___output(ae,0x9E);ae->nop+=2;break; + case CRC_B:___output(ae,0x98);ae->nop+=1;break; + case CRC_C:___output(ae,0x99);ae->nop+=1;break; + case CRC_D:___output(ae,0x9A);ae->nop+=1;break; + case CRC_E:___output(ae,0x9B);ae->nop+=1;break; + case CRC_H:___output(ae,0x9C);ae->nop+=1;break; + case CRC_L:___output(ae,0x9D);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x9C);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x9D);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x9C);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x9D);ae->nop+=2;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SBC with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x9E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=3; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x9E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=3; + } else { + ___output(ae,0xDE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xED);___output(ae,0x42);ae->nop+=4;break; + case CRC_DE:___output(ae,0xED);___output(ae,0x52);ae->nop+=4;break; + case CRC_HL:___output(ae,0xED);___output(ae,0x62);ae->nop+=4;break; + case CRC_SP:___output(ae,0xED);___output(ae,0x72);ae->nop+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SBC HL,[BC,DE,HL,SP]\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SBC HL,[BC,DE,HL,SP]\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for SBC\n"); + } +} + +void _ADC(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* also implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x8F);ae->nop+=1;break; + case CRC_MHL:___output(ae,0x8E);ae->nop+=2;break; + case CRC_B:___output(ae,0x88);ae->nop+=1;break; + case CRC_C:___output(ae,0x89);ae->nop+=1;break; + case CRC_D:___output(ae,0x8A);ae->nop+=1;break; + case CRC_E:___output(ae,0x8B);ae->nop+=1;break; + case CRC_H:___output(ae,0x8C);ae->nop+=1;break; + case CRC_L:___output(ae,0x8D);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x8C);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x8D);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x8C);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x8D);ae->nop+=2;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use ADC with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x8E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=3; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x8E); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=3; + } else { + ___output(ae,0xCE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xED);___output(ae,0x4A);ae->nop+=4;break; + case CRC_DE:___output(ae,0xED);___output(ae,0x5A);ae->nop+=4;break; + case CRC_HL:___output(ae,0xED);___output(ae,0x6A);ae->nop+=4;break; + case CRC_SP:___output(ae,0xED);___output(ae,0x7A);ae->nop+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADC HL,[BC,DE,HL,SP]\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADC HL,[BC,DE,HL,SP]\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for ADC\n"); + } +} + +void _ADD(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* also implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x87);ae->nop+=1;break; + case CRC_MHL:___output(ae,0x86);ae->nop+=2;break; + case CRC_B:___output(ae,0x80);ae->nop+=1;break; + case CRC_C:___output(ae,0x81);ae->nop+=1;break; + case CRC_D:___output(ae,0x82);ae->nop+=1;break; + case CRC_E:___output(ae,0x83);ae->nop+=1;break; + case CRC_H:___output(ae,0x84);ae->nop+=1;break; + case CRC_L:___output(ae,0x85);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x84);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x85);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x84);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x85);ae->nop+=2;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use ADD with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x86); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x86); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0xC6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x09);ae->nop+=3;break; + case CRC_DE:___output(ae,0x19);ae->nop+=3;break; + case CRC_HL:___output(ae,0x29);ae->nop+=3;break; + case CRC_SP:___output(ae,0x39);ae->nop+=3;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD HL,[BC,DE,HL,SP]\n"); + } + break; + case CRC_IX: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xDD);___output(ae,0x09);ae->nop+=4;break; + case CRC_DE:___output(ae,0xDD);___output(ae,0x19);ae->nop+=4;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x29);ae->nop+=4;break; + case CRC_SP:___output(ae,0xDD);___output(ae,0x39);ae->nop+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD IX,[BC,DE,IX,SP]\n"); + } + break; + case CRC_IY: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0xFD);___output(ae,0x09);ae->nop+=4;break; + case CRC_DE:___output(ae,0xFD);___output(ae,0x19);ae->nop+=4;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x29);ae->nop+=4;break; + case CRC_SP:___output(ae,0xFD);___output(ae,0x39);ae->nop+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD IY,[BC,DE,IY,SP]\n"); + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is ADD [HL,IX,IY],reg16\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid syntax for ADD\n"); + } +} + +void _CP(struct s_assenv *ae) { + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + /* also implicit A */ + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0xBF);ae->nop+=1;break; + case CRC_MHL:___output(ae,0xBE);ae->nop+=2;break; + case CRC_B:___output(ae,0xB8);ae->nop+=1;break; + case CRC_C:___output(ae,0xB9);ae->nop+=1;break; + case CRC_D:___output(ae,0xBA);ae->nop+=1;break; + case CRC_E:___output(ae,0xBB);ae->nop+=1;break; + case CRC_H:___output(ae,0xBC);ae->nop+=1;break; + case CRC_L:___output(ae,0xBD);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0xBC);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0xBD);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0xBC);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0xBD);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xBE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xBE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0xFE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is CP reg8/(reg16)\n"); + } +} + +void _RET(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_NZ:___output(ae,0xC0);ae->nop+=2;break; + case CRC_Z:___output(ae,0xC8);ae->nop+=2;break; + case CRC_C:___output(ae,0xD8);ae->nop+=2;break; + case CRC_NC:___output(ae,0xD0);ae->nop+=2;break; + case CRC_PE:___output(ae,0xE8);ae->nop+=2;break; + case CRC_PO:___output(ae,0xE0);ae->nop+=2;break; + case CRC_P:___output(ae,0xF0);ae->nop+=2;break; + case CRC_M:___output(ae,0xF8);ae->nop+=2;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for RET are C,NC,Z,NZ,PE,PO,P,M\n"); + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ___output(ae,0xC9); + ae->nop+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid RET syntax\n"); + } +} + +void _CALL(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_C:___output(ae,0xDC);ae->nop+=3;break; + case CRC_Z:___output(ae,0xCC);ae->nop+=3;break; + case CRC_NZ:___output(ae,0xC4);ae->nop+=3;break; + case CRC_NC:___output(ae,0xD4);ae->nop+=3;break; + case CRC_PE:___output(ae,0xEC);ae->nop+=3;break; + case CRC_PO:___output(ae,0xE4);ae->nop+=3;break; + case CRC_P:___output(ae,0xF4);ae->nop+=3;break; + case CRC_M:___output(ae,0xFC);ae->nop+=3;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for CALL are C,NC,Z,NZ,PE,PO,P,M\n"); + } + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16C); + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ___output(ae,0xCD); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V16C); + ae->idx++; + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid CALL syntax\n"); + } +} + +void _JR(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_NZ:___output(ae,0x20);ae->nop+=2;break; + case CRC_C:___output(ae,0x38);ae->nop+=2;break; + case CRC_Z:___output(ae,0x28);ae->nop+=2;break; + case CRC_NC:___output(ae,0x30);ae->nop+=2;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for JR are C,NC,Z,NZ\n"); + } + PushExpression(ae,ae->idx+2,E_EXPRESSION_J8); + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ___output(ae,0x18); + PushExpression(ae,ae->idx+1,E_EXPRESSION_J8); + ae->idx++; + ae->nop+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid JR syntax\n"); + } +} + +void _JP(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_C:___output(ae,0xDA);ae->nop+=3;break; + case CRC_Z:___output(ae,0xCA);ae->nop+=3;break; + case CRC_NZ:___output(ae,0xC2);ae->nop+=3;break; + case CRC_NC:___output(ae,0xD2);ae->nop+=3;break; + case CRC_PE:___output(ae,0xEA);ae->nop+=3;break; + case CRC_PO:___output(ae,0xE2);ae->nop+=3;break; + case CRC_P:___output(ae,0xF2);ae->nop+=3;break; + case CRC_M:___output(ae,0xFA);ae->nop+=3;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Available flags for JP are C,NC,Z,NZ,PE,PO,P,M\n"); + } + if (!strcmp(ae->wl[ae->idx+2].w,"(IX)") || !strcmp(ae->wl[ae->idx+2].w,"(IY)")) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"conditionnal JP cannot use register adressing\n"); + } else { + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + } + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_HL:case CRC_MHL:___output(ae,0xE9);ae->nop+=1;break; + case CRC_IX:case CRC_MIX:___output(ae,0xDD);___output(ae,0xE9);ae->nop+=2;break; + case CRC_IY:case CRC_MIY:___output(ae,0xFD);___output(ae,0xE9);ae->nop+=2;break; + default: + ___output(ae,0xC3); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V16); + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid JP syntax\n"); + } +} + + +void _DEC(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x3D);ae->nop+=1;break; + case CRC_B:___output(ae,0x05);ae->nop+=1;break; + case CRC_C:___output(ae,0x0D);ae->nop+=1;break; + case CRC_D:___output(ae,0x15);ae->nop+=1;break; + case CRC_E:___output(ae,0x1D);ae->nop+=1;break; + case CRC_H:___output(ae,0x25);ae->nop+=1;break; + case CRC_L:___output(ae,0x2D);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x25);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x2D);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x25);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x2D);ae->nop+=2;break; + case CRC_BC:___output(ae,0x0B);ae->nop+=2;break; + case CRC_DE:___output(ae,0x1B);ae->nop+=2;break; + case CRC_HL:___output(ae,0x2B);ae->nop+=2;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x2B);ae->nop+=3;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x2B);ae->nop+=3;break; + case CRC_SP:___output(ae,0x3B);ae->nop+=2;break; + case CRC_MHL:___output(ae,0x35);ae->nop+=3;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x35); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x35); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use DEC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } + } + ae->idx++; + } while (ae->wl[ae->idx].t==0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use DEC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } +} +void _INC(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,0x3C);ae->nop+=1;break; + case CRC_B:___output(ae,0x04);ae->nop+=1;break; + case CRC_C:___output(ae,0x0C);ae->nop+=1;break; + case CRC_D:___output(ae,0x14);ae->nop+=1;break; + case CRC_E:___output(ae,0x1C);ae->nop+=1;break; + case CRC_H:___output(ae,0x24);ae->nop+=1;break; + case CRC_L:___output(ae,0x2C);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x24);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x2C);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x24);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x2C);ae->nop+=2;break; + case CRC_BC:___output(ae,0x03);ae->nop+=2;break; + case CRC_DE:___output(ae,0x13);ae->nop+=2;break; + case CRC_HL:___output(ae,0x23);ae->nop+=2;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x23);ae->nop+=3;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x23);ae->nop+=3;break; + case CRC_SP:___output(ae,0x33);ae->nop+=2;break; + case CRC_MHL:___output(ae,0x34);ae->nop+=3;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x34); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x34); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=6; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use INC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } + } + ae->idx++; + } while (ae->wl[ae->idx].t==0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use INC with A,B,C,D,E,H,L,XH,XL,YH,YL,BC,DE,HL,SP,(HL),(IX),(IY)\n"); + } +} + +void _SUB(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0x90 + + if ((!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) || ((!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) && strcmp(ae->wl[ae->idx+1].w,"A")==0)) { + if (!ae->wl[ae->idx+1].t) ae->idx++; + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; + case CRC_IX:case CRC_IY: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SUB with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + ae->idx++; + return; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0xD6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SUB with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} +void _AND(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0xA0 + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0xE6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use AND with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} +void _OR(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0xB0 + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0xF6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use OR with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} +void _XOR(struct s_assenv *ae) { + #ifdef OPCODE + #undef OPCODE + #endif + #define OPCODE 0xA8 + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A:___output(ae,OPCODE+7);ae->nop+=1;break; + case CRC_MHL:___output(ae,OPCODE+6);ae->nop+=2;break; + case CRC_B:___output(ae,OPCODE);ae->nop+=1;break; + case CRC_C:___output(ae,OPCODE+1);ae->nop+=1;break; + case CRC_D:___output(ae,OPCODE+2);ae->nop+=1;break; + case CRC_E:___output(ae,OPCODE+3);ae->nop+=1;break; + case CRC_H:___output(ae,OPCODE+4);ae->nop+=1;break; + case CRC_L:___output(ae,OPCODE+5);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,OPCODE+5);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,OPCODE+4);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,OPCODE+5);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,OPCODE+6); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0xEE); + PushExpression(ae,ae->idx+1,E_EXPRESSION_V8); + ae->nop+=2; + } + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use XOR with A,B,C,D,E,H,L,XH,XL,YH,YL,(HL),(IX),(IY)\n"); + } +} + + +void _POP(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + switch (GetCRC(ae->wl[ae->idx].w)) { + case CRC_AF:___output(ae,0xF1);ae->nop+=3;break; + case CRC_BC:___output(ae,0xC1);ae->nop+=3;break; + case CRC_DE:___output(ae,0xD1);ae->nop+=3;break; + case CRC_HL:___output(ae,0xE1);ae->nop+=3;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xE1);ae->nop+=4;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xE1);ae->nop+=4;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use POP with AF,BC,DE,HL,IX,IY\n"); + } + } while (ae->wl[ae->idx].t!=1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"POP need at least one parameter\n"); + } +} +void _PUSH(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + switch (GetCRC(ae->wl[ae->idx].w)) { + case CRC_AF:___output(ae,0xF5);ae->nop+=4;break; + case CRC_BC:___output(ae,0xC5);ae->nop+=4;break; + case CRC_DE:___output(ae,0xD5);ae->nop+=4;break; + case CRC_HL:___output(ae,0xE5);ae->nop+=4;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xE5);ae->nop+=5;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xE5);ae->nop+=5;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use PUSH with AF,BC,DE,HL,IX,IY\n"); + } + } while (ae->wl[ae->idx].t!=1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PUSH need at least one parameter\n"); + } +} + +void _IM(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* la valeur du parametre va definir l'opcode du IM */ + ___output(ae,0xED); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IM); + ae->idx++; + ae->nop+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IM need one parameter\n"); + } +} + +void _RLCA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x7); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLCA does not need parameter\n"); + } +} +void _RRCA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xF); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRCA does not need parameter\n"); + } +} +void _NEG(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0x44); + ae->nop+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NEG does not need parameter\n"); + } +} +void _DAA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x27); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DAA does not need parameter\n"); + } +} +void _CPL(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x2F); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPL does not need parameter\n"); + } +} +void _RETI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0x4D); + ae->nop+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RETI does not need parameter\n"); + } +} +void _SCF(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x37); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SCF does not need parameter\n"); + } +} +void _LDD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA8); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDD does not need parameter\n"); + } +} +void _LDDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB8); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDDR does not need parameter\n"); + } +} +void _LDI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA0); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDI does not need parameter\n"); + } +} +void _LDIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB0); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LDIR does not need parameter\n"); + } +} +void _CCF(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0x3F); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CCF does not need parameter\n"); + } +} +void _CPD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA9); + ae->nop+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPD does not need parameter\n"); + } +} +void _CPDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB9); + ae->nop+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPDR does not need parameter\n"); + } +} +void _CPI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA1); + ae->nop+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPI does not need parameter\n"); + } +} +void _CPIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB1); + ae->nop+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CPIR does not need parameter\n"); + } +} +void _OUTD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xAB); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUTD does not need parameter\n"); + } +} +void _OTDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xBB); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OTDR does not need parameter\n"); + } +} +void _OUTI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA3); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OUTI does not need parameter\n"); + } +} +void _OTIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xB3); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"OTIR does not need parameter\n"); + } +} +void _RETN(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0x45); + ae->nop+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RETN does not need parameter\n"); + } +} +void _IND(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xAA); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IND does not need parameter\n"); + } +} +void _INDR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xBA); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INDR does not need parameter\n"); + } +} +void _INI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xED); + ___output(ae,0xA2); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INI does not need parameter\n"); + } +} +void _INIR(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xED); + ___output(ae,0xB2); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INIR does not need parameter\n"); + } +} +void _EXX(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xD9); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EXX does not need parameter\n"); + } +} +void _HALT(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x76); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"HALT does not need parameter\n"); + } +} + +void _RLA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x17); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLA does not need parameter\n"); + } +} +void _RRA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x1F); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRA does not need parameter\n"); + } +} +void _RLD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xED); + ___output(ae,0x6F); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RLD does not need parameter\n"); + } +} +void _RRD(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0xED); + ___output(ae,0x67); + ae->nop+=5; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RRD does not need parameter\n"); + } +} + + +void _EXA(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___output(ae,0x08);ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EXA alias does not need parameter\n"); + } +} + +void _NOP(struct s_assenv *ae) { + int o; + + if (ae->wl[ae->idx].t) { + ___output(ae,0x00); + ae->nop+=1; + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (o>=0) { + while (o>0) { + ___output(ae,0x00); + ae->nop+=1; + o--; + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOP is supposed to be used without parameter or with one optional parameter\n"); + } +} +void _DI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xF3); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DI does not need parameter\n"); + } +} +void _EI(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___output(ae,0xFB); + ae->nop+=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"EI does not need parameter\n"); + } +} + +void _RST(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t!=2) { + if (!strcmp(ae->wl[ae->idx+1].w,"(IY)") || !strcmp(ae->wl[ae->idx+1].w,"(IX)")) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RST cannot use IX or IY\n"); + } else { + /* la valeur du parametre va definir l'opcode du RST */ + PushExpression(ae,ae->idx+1,E_EXPRESSION_RST); + } + ae->idx++; + ae->nop+=4; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"RST need one parameter\n"); + } +} + +void _DJNZ(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + if (IsRegister(ae->wl[ae->idx+1].w)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ cannot use register\n"); + } else if (strcmp("(IX)",ae->wl[ae->idx+1].w)==0 || strcmp("(IY)",ae->wl[ae->idx+1].w)==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ cannot use register\n"); + } else { + ___output(ae,0x10); + PushExpression(ae,ae->idx+1,E_EXPRESSION_J8); + ae->nop+=3; + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DJNZ need one parameter\n"); + } +} + +void _LD(struct s_assenv *ae) { + /* on check qu'il y a au moins deux parametres */ + if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_A: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_I:___output(ae,0xED);___output(ae,0x57);ae->nop+=3;break; + case CRC_R:___output(ae,0xED);___output(ae,0x5F);ae->nop+=3;break; + case CRC_B:___output(ae,0x78);ae->nop+=1;break; + case CRC_C:___output(ae,0x79);ae->nop+=1;break; + case CRC_D:___output(ae,0x7A);ae->nop+=1;break; + case CRC_E:___output(ae,0x7B);ae->nop+=1;break; + case CRC_H:___output(ae,0x7C);ae->nop+=1;break; + case CRC_L:___output(ae,0x7D);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x7C);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x7D);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x7C);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x7D);ae->nop+=2;break; + case CRC_MHL:___output(ae,0x7E);ae->nop+=2;break; + case CRC_A:___output(ae,0x7F);ae->nop+=1;break; + case CRC_MBC:___output(ae,0x0A);ae->nop+=2;break; + case CRC_MDE:___output(ae,0x1A);ae->nop+=2;break; + default: + /* (ix+expression) (iy+expression) (expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x7E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x7E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0x3A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=4; + } else { + ___output(ae,0x3E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2; + } + } + break; + case CRC_I: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0xED);___output(ae,0x47); + ae->nop+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD I,A only\n"); + } + break; + case CRC_R: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0xED);___output(ae,0x4F); + ae->nop+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD R,A only\n"); + } + break; + case CRC_B: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x40);ae->nop+=1;break; + case CRC_C:___output(ae,0x41);ae->nop+=1;break; + case CRC_D:___output(ae,0x42);ae->nop+=1;break; + case CRC_E:___output(ae,0x43);ae->nop+=1;break; + case CRC_H:___output(ae,0x44);ae->nop+=1;break; + case CRC_L:___output(ae,0x45);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x44);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x45);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x44);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x45);ae->nop+=2;break; + case CRC_MHL:___output(ae,0x46);ae->nop+=2;break; + case CRC_A:___output(ae,0x47);ae->nop+=1;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0x06); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2; + } + } + break; + case CRC_C: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x48);ae->nop+=1;break; + case CRC_C:___output(ae,0x49);ae->nop+=1;break; + case CRC_D:___output(ae,0x4A);ae->nop+=1;break; + case CRC_E:___output(ae,0x4B);ae->nop+=1;break; + case CRC_H:___output(ae,0x4C);ae->nop+=1;break; + case CRC_L:___output(ae,0x4D);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x4C);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x4D);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x4C);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x4D);ae->nop+=2;break; + case CRC_MHL:___output(ae,0x4E);ae->nop+=2;break; + case CRC_A:___output(ae,0x4F);ae->nop+=1;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0x0E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2; + } + } + break; + case CRC_D: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x50);ae->nop+=1;break; + case CRC_C:___output(ae,0x51);ae->nop+=1;break; + case CRC_D:___output(ae,0x52);ae->nop+=1;break; + case CRC_E:___output(ae,0x53);ae->nop+=1;break; + case CRC_H:___output(ae,0x54);ae->nop+=1;break; + case CRC_L:___output(ae,0x55);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x54);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x55);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x54);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x55);ae->nop+=2;break; + case CRC_MHL:___output(ae,0x56);ae->nop+=2;break; + case CRC_A:___output(ae,0x57);ae->nop+=1;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0x16); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2; + } + } + break; + case CRC_E: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x58);ae->nop+=1;break; + case CRC_C:___output(ae,0x59);ae->nop+=1;break; + case CRC_D:___output(ae,0x5A);ae->nop+=1;break; + case CRC_E:___output(ae,0x5B);ae->nop+=1;break; + case CRC_H:___output(ae,0x5C);ae->nop+=1;break; + case CRC_L:___output(ae,0x5D);ae->nop+=1;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x5C);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x5D);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x5C);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x5D);ae->nop+=2;break; + case CRC_MHL:___output(ae,0x5E);ae->nop+=2;break; + case CRC_A:___output(ae,0x5F);ae->nop+=1;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0x1E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2; + } + } + break; + case CRC_IYH:case CRC_HY:case CRC_YH: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xFD);___output(ae,0x60);ae->nop+=2;break; + case CRC_C:___output(ae,0xFD);___output(ae,0x61);ae->nop+=2;break; + case CRC_D:___output(ae,0xFD);___output(ae,0x62);ae->nop+=2;break; + case CRC_E:___output(ae,0xFD);___output(ae,0x63);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x64);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x65);ae->nop+=2;break; + case CRC_A:___output(ae,0xFD);___output(ae,0x67);ae->nop+=2;break; + default: + ___output(ae,0xFD);___output(ae,0x26); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3; + } + break; + case CRC_IYL:case CRC_LY:case CRC_YL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xFD);___output(ae,0x68);ae->nop+=2;break; + case CRC_C:___output(ae,0xFD);___output(ae,0x69);ae->nop+=2;break; + case CRC_D:___output(ae,0xFD);___output(ae,0x6A);ae->nop+=2;break; + case CRC_E:___output(ae,0xFD);___output(ae,0x6B);ae->nop+=2;break; + case CRC_IYH:case CRC_HY:case CRC_YH:___output(ae,0xFD);___output(ae,0x6C);ae->nop+=2;break; + case CRC_IYL:case CRC_LY:case CRC_YL:___output(ae,0xFD);___output(ae,0x6D);ae->nop+=2;break; + case CRC_A:___output(ae,0xFD);___output(ae,0x6F);ae->nop+=2;break; + default: + ___output(ae,0xFD);___output(ae,0x2E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3; + } + break; + case CRC_IXH:case CRC_HX:case CRC_XH: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xDD);___output(ae,0x60);ae->nop+=2;break; + case CRC_C:___output(ae,0xDD);___output(ae,0x61);ae->nop+=2;break; + case CRC_D:___output(ae,0xDD);___output(ae,0x62);ae->nop+=2;break; + case CRC_E:___output(ae,0xDD);___output(ae,0x63);ae->nop+=2;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x64);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x65);ae->nop+=2;break; + case CRC_A:___output(ae,0xDD);___output(ae,0x67);ae->nop+=2;break; + default: + ___output(ae,0xDD);___output(ae,0x26); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3; + } + break; + case CRC_IXL:case CRC_LX:case CRC_XL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xDD);___output(ae,0x68);ae->nop+=2;break; + case CRC_C:___output(ae,0xDD);___output(ae,0x69);ae->nop+=2;break; + case CRC_D:___output(ae,0xDD);___output(ae,0x6A);ae->nop+=2;break; + case CRC_E:___output(ae,0xDD);___output(ae,0x6B);ae->nop+=2;break; + case CRC_IXH:case CRC_HX:case CRC_XH:___output(ae,0xDD);___output(ae,0x6C);ae->nop+=2;break; + case CRC_IXL:case CRC_LX:case CRC_XL:___output(ae,0xDD);___output(ae,0x6D);ae->nop+=2;break; + case CRC_A:___output(ae,0xDD);___output(ae,0x6F);ae->nop+=2;break; + default: + ___output(ae,0xDD);___output(ae,0x2E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3; + } + break; + case CRC_H: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x60);ae->nop+=1;break; + case CRC_C:___output(ae,0x61);ae->nop+=1;break; + case CRC_D:___output(ae,0x62);ae->nop+=1;break; + case CRC_E:___output(ae,0x63);ae->nop+=1;break; + case CRC_H:___output(ae,0x64);ae->nop+=1;break; + case CRC_L:___output(ae,0x65);ae->nop+=1;break; + case CRC_MHL:___output(ae,0x66);ae->nop+=2;break; + case CRC_A:___output(ae,0x67);ae->nop+=1;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0x26); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2; + } + } + break; + case CRC_L: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x68);ae->nop+=1;break; + case CRC_C:___output(ae,0x69);ae->nop+=1;break; + case CRC_D:___output(ae,0x6A);ae->nop+=1;break; + case CRC_E:___output(ae,0x6B);ae->nop+=1;break; + case CRC_H:___output(ae,0x6C);ae->nop+=1;break; + case CRC_L:___output(ae,0x6D);ae->nop+=1;break; + case CRC_MHL:___output(ae,0x6E);ae->nop+=2;break; + case CRC_A:___output(ae,0x6F);ae->nop+=1;break; + default: + /* (ix+expression) (iy+expression) expression */ + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=5; + } else { + ___output(ae,0x2E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=2; + } + } + break; + case CRC_MHL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0x70);ae->nop+=2;break; + case CRC_C:___output(ae,0x71);ae->nop+=2;break; + case CRC_D:___output(ae,0x72);ae->nop+=2;break; + case CRC_E:___output(ae,0x73);ae->nop+=2;break; + case CRC_H:___output(ae,0x74);ae->nop+=2;break; + case CRC_L:___output(ae,0x75);ae->nop+=2;break; + case CRC_A:___output(ae,0x77);ae->nop+=2;break; + default: + /* expression */ + ___output(ae,0x36); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V8); + ae->nop+=3; + } + break; + case CRC_MBC: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0x02); + ae->nop+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (BC),A only\n"); + } + break; + case CRC_MDE: + if (GetCRC(ae->wl[ae->idx+2].w)==CRC_A) { + ___output(ae,0x12); + ae->nop+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (DE),A only\n"); + } + break; + case CRC_HL: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x60);___output(ae,0x69);ae->nop+=2;break; + case CRC_DE:___output(ae,0x62);___output(ae,0x6B);ae->nop+=2;break; + case CRC_HL:___output(ae,0x64);___output(ae,0x6D);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX+",4)==0) { + /* enhanced LD HL,(IX+nn) */ + ___output(ae,0xDD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xDD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY+",4)==0) { + /* enhanced LD HL,(IY+nn) */ + ___output(ae,0xFD);___output(ae,0x66); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xFD);___output(ae,0x6E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0x2A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=5; + } else { + ___output(ae,0x21); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3; + } + } + break; + case CRC_BC: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x40);___output(ae,0x49);ae->nop+=2;break; + case CRC_DE:___output(ae,0x42);___output(ae,0x4B);ae->nop+=2;break; + case CRC_HL:___output(ae,0x44);___output(ae,0x4D);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX+",4)==0) { + /* enhanced LD BC,(IX+nn) */ + ___output(ae,0xDD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xDD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY+",4)==0) { + /* enhanced LD BC,(IY+nn) */ + ___output(ae,0xFD);___output(ae,0x46); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xFD);___output(ae,0x4E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xED);___output(ae,0x4B); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6; + } else { + ___output(ae,0x01); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3; + } + } + break; + case CRC_DE: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_BC:___output(ae,0x50);___output(ae,0x59);ae->nop+=2;break; + case CRC_DE:___output(ae,0x52);___output(ae,0x5B);ae->nop+=2;break; + case CRC_HL:___output(ae,0x54);___output(ae,0x5D);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX+",4)==0) { + /* enhanced LD DE,(IX+nn) */ + ___output(ae,0xDD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xDD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY+",4)==0) { + /* enhanced LD DE,(IY+nn) */ + ___output(ae,0xFD);___output(ae,0x56); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV81); + ___output(ae,0xFD);___output(ae,0x5E); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ae->nop+=10; + } else if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xED);___output(ae,0x5B); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6; + } else { + ___output(ae,0x11); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3; + } + } + break; + case CRC_IX: + if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xDD);___output(ae,0x2A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6; + } else { + ___output(ae,0xDD);___output(ae,0x21); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=4; + } + break; + case CRC_IY: + if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xFD);___output(ae,0x2A); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6; + } else { + ___output(ae,0xFD);___output(ae,0x21); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=4; + } + break; + case CRC_SP: + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_HL:___output(ae,0xF9);ae->nop+=2;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0xF9);ae->nop+=3;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0xF9);ae->nop+=3;break; + default: + if (StringIsMem(ae->wl[ae->idx+2].w)) { + ___output(ae,0xED);___output(ae,0x7B); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV16); + ae->nop+=6; + } else { + ___output(ae,0x31); + PushExpression(ae,ae->idx+2,E_EXPRESSION_V16); + ae->nop+=3; + } + } + break; + default: + /* (ix+expression) (iy+expression) (expression) expression */ + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xDD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_C:___output(ae,0xDD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_D:___output(ae,0xDD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_E:___output(ae,0xDD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_H:___output(ae,0xDD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_L:___output(ae,0xDD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_A:___output(ae,0xDD);___output(ae,0x77);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_HL:___output(ae,0xDD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; + case CRC_DE:___output(ae,0xDD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; + case CRC_BC:___output(ae,0xDD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xDD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; + default:___output(ae,0xDD);___output(ae,0x36); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+2,E_EXPRESSION_3V8); + ae->nop+=6; + } + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xFD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_C:___output(ae,0xFD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_D:___output(ae,0xFD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_E:___output(ae,0xFD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_H:___output(ae,0xFD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_L:___output(ae,0xFD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_A:___output(ae,0xFD);___output(ae,0x77);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=5;break; + case CRC_HL:___output(ae,0xFD);___output(ae,0x74);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x75);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; + case CRC_DE:___output(ae,0xFD);___output(ae,0x72);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; + case CRC_BC:___output(ae,0xFD);___output(ae,0x70);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV81);___output(ae,0xFD);___output(ae,0x71);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);ae->nop+=10;break; + default:___output(ae,0xFD);___output(ae,0x36); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + PushExpression(ae,ae->idx+2,E_EXPRESSION_3V8); + ae->nop+=6; + } + } else if (StringIsMem(ae->wl[ae->idx+1].w)) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_A:___output(ae,0x32);PushExpression(ae,ae->idx+1,E_EXPRESSION_V16);ae->nop+=4;break; + case CRC_BC:___output(ae,0xED);___output(ae,0x43);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; + case CRC_DE:___output(ae,0xED);___output(ae,0x53);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; + case CRC_HL:___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_V16);ae->nop+=5;break; + case CRC_IX:___output(ae,0xDD);___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; + case CRC_IY:___output(ae,0xFD);___output(ae,0x22);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; + case CRC_SP:___output(ae,0xED);___output(ae,0x73);PushExpression(ae,ae->idx+1,E_EXPRESSION_IV16);ae->nop+=6;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD (#nnnn),[A,BC,DE,HL,SP,IX,IY] only\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Unknown LD format\n"); + } + break; + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LD needs two parameters\n"); + } +} + + +void _RLC(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_B:___output(ae,0xCB);___output(ae,0x0);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x1);ae->nop+=2;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x2);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x3);ae->nop+=2;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x4);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x5);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x6);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x7);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x6); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x6); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x0);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x4);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x5);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x7);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RLC (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } +} + +void _RRC(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_B:___output(ae,0xCB);___output(ae,0x8);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x9);ae->nop+=2;break; + case CRC_D:___output(ae,0xCB);___output(ae,0xA);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0xB);ae->nop+=2;break; + case CRC_H:___output(ae,0xCB);___output(ae,0xC);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0xD);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0xE);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0xF);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0xE); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0xE); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x8);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x9);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xA);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xB);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xC);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xD);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0xF);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RRC (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } +} + + +void _RL(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x10);___output(ae,0xCB);___output(ae,0x11);ae->nop+=4;break; + case CRC_B:___output(ae,0xCB);___output(ae,0x10);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x11);ae->nop+=2;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x12);___output(ae,0xCB);___output(ae,0x13);ae->nop+=4;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x12);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x13);ae->nop+=2;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x14);___output(ae,0xCB);___output(ae,0x15);ae->nop+=4;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x14);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x15);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x16);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x17);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x16); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x16); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x10);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x11);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x12);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x13);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x14);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x15);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x17);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RL (IX+n),reg8 or RL reg8/(HL)/(IX+n)/(IY+n)\n"); + } +} + +void _RR(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x18);___output(ae,0xCB);___output(ae,0x19);ae->nop+=4;break; + case CRC_B:___output(ae,0xCB);___output(ae,0x18);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x19);ae->nop+=2;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x1A);___output(ae,0xCB);___output(ae,0x1B);ae->nop+=4;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x1A);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x1B);ae->nop+=2;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x1C);___output(ae,0xCB);___output(ae,0x1D);ae->nop+=4;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x1C);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x1D);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x1E);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x1F);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x1E); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x1E); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x18);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x19);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1A);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1B);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1C);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1D);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x1F);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RR (IX+n),reg8 or RR reg8/(HL)/(IX+n)/(IY+n)\n"); + } +} + + + + + +void _SLA(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x21);___output(ae,0xCB);___output(ae,0x10);ae->nop+=4;break; /* SLA C : RL B */ + case CRC_B:___output(ae,0xCB);___output(ae,0x20);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x21);ae->nop+=2;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x23);___output(ae,0xCB);___output(ae,0x12);ae->nop+=4;break; /* SLA E : RL D */ + case CRC_D:___output(ae,0xCB);___output(ae,0x22);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x23);ae->nop+=2;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x25);___output(ae,0xCB);___output(ae,0x14);ae->nop+=4;break; /* SLA L : RL H */ + case CRC_H:___output(ae,0xCB);___output(ae,0x24);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x25);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x26);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x27);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x26); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x26); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x20);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x21);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x22);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x23);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x24);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x25);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x27);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLA reg8/(HL)/(IX+n)/(IY+n) or SLA (IX+n),reg8\n"); + } +} + +void _SRA(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x28);___output(ae,0xCB);___output(ae,0x19);ae->nop+=4;break; /* SRA B : RR C */ + case CRC_B:___output(ae,0xCB);___output(ae,0x28);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x29);ae->nop+=2;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x2A);___output(ae,0xCB);___output(ae,0x1B);ae->nop+=4;break; /* SRA D : RR E */ + case CRC_D:___output(ae,0xCB);___output(ae,0x2A);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x2B);ae->nop+=2;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x2C);___output(ae,0xCB);___output(ae,0x1D);ae->nop+=4;break; /* SRA H : RR L */ + case CRC_H:___output(ae,0xCB);___output(ae,0x2C);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x2D);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x2E);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x2F);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x2E); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x2E); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x28);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x29);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2A);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2B);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2C);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2D);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x2F);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRA reg8/(HL)/(IX+n)/(IY+n) or SRA (IX+n),reg8\n"); + } +} + + +void _SLL(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x31);___output(ae,0xCB);___output(ae,0x10);ae->nop+=4;break; /* SLL C : RL B */ + case CRC_B:___output(ae,0xCB);___output(ae,0x30);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x31);ae->nop+=2;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x33);___output(ae,0xCB);___output(ae,0x12);ae->nop+=4;break; /* SLL E : RL D */ + case CRC_D:___output(ae,0xCB);___output(ae,0x32);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x33);ae->nop+=2;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x35);___output(ae,0xCB);___output(ae,0x14);ae->nop+=4;break; /* SLL L : RL H */ + case CRC_H:___output(ae,0xCB);___output(ae,0x34);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x35);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x36);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x37);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x36); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x36); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x30);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x31);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x32);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x33);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x34);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x35);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x37);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SLL reg8/(HL)/(IX+n)/(IY+n) or SLL (IX+n),reg8\n"); + } +} + +void _SRL(struct s_assenv *ae) { + /* on check qu'il y a un ou deux parametres */ + if (ae->wl[ae->idx+1].t==1) { + switch (GetCRC(ae->wl[ae->idx+1].w)) { + case CRC_BC:___output(ae,0xCB);___output(ae,0x38);___output(ae,0xCB);___output(ae,0x11);ae->nop+=4;break; /* SRL B : RL C */ + case CRC_B:___output(ae,0xCB);___output(ae,0x38);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x39);ae->nop+=2;break; + case CRC_DE:___output(ae,0xCB);___output(ae,0x3A);___output(ae,0xCB);___output(ae,0x13);ae->nop+=4;break; /* SRL D : RL E */ + case CRC_D:___output(ae,0xCB);___output(ae,0x3A);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x3B);ae->nop+=2;break; + case CRC_HL:___output(ae,0xCB);___output(ae,0x3C);___output(ae,0xCB);___output(ae,0x15);ae->nop+=4;break; /* SRL H : RL L */ + case CRC_H:___output(ae,0xCB);___output(ae,0x3C);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x3D);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x3E);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x3F);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x3E); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8); + ___output(ae,0x3E); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx++; + } else if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + if (strncmp(ae->wl[ae->idx+1].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+1].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x38);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x39);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3A);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3B);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3C);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3D);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+1,E_EXPRESSION_IV8);___output(ae,0x3F);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL (IX+n),reg8\n"); + } + ae->idx++; + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SRL reg8/(HL)/(IX+n)/(IY+n) or SRL (IX+n),reg8\n"); + } +} + + +void _BIT(struct s_assenv *ae) { + int o; + /* on check qu'il y a deux ou trois parametres */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (o<0 || o>7) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT <value from 0 to 7>,... (%d)\n",o); + } else { + o=0x40+o*8; + if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xCB);___output(ae,0x0+o);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x1+o);ae->nop+=2;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x2+o);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x3+o);ae->nop+=2;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x4+o);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x5+o);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x6+o);ae->nop+=3;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x7+o);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ___output(ae,0x6+o); + ae->nop+=6; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ___output(ae,0x6+o); + ae->nop+=6; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT (IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+3].w)) { + case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x0+o);ae->nop+=6;break; + case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x1+o);ae->nop+=6;break; + case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x2+o);ae->nop+=6;break; + case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x3+o);ae->nop+=6;break; + case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x4+o);ae->nop+=6;break; + case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x5+o);ae->nop+=6;break; + case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x7+o);ae->nop+=6;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,(IX+n),reg8\n"); + } + ae->idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BIT n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); + } + } +} + +void _RES(struct s_assenv *ae) { + int o; + /* on check qu'il y a deux ou trois parametres */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (o<0 || o>7) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES <value from 0 to 7>,... (%d)\n",o); + } else { + o=0x80+o*8; + if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xCB);___output(ae,0x0+o);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x1+o);ae->nop+=2;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x2+o);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x3+o);ae->nop+=2;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x4+o);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x5+o);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x6+o);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x7+o);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ___output(ae,0x6+o); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ___output(ae,0x6+o); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,(IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+3].w)) { + case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x0+o);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x1+o);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x2+o);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x3+o);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x4+o);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x5+o);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x7+o);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,(IX+n),reg8\n"); + } + ae->idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is RES n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); + } + } +} + +void _SET(struct s_assenv *ae) { + int o; + /* on check qu'il y a deux ou trois parametres */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + o=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (o<0 || o>7) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET <value from 0 to 7>,... (%d)\n",o); + } else { + o=0xC0+o*8; + if (ae->wl[ae->idx+1].t==0 && ae->wl[ae->idx+2].t==1) { + switch (GetCRC(ae->wl[ae->idx+2].w)) { + case CRC_B:___output(ae,0xCB);___output(ae,0x0+o);ae->nop+=2;break; + case CRC_C:___output(ae,0xCB);___output(ae,0x1+o);ae->nop+=2;break; + case CRC_D:___output(ae,0xCB);___output(ae,0x2+o);ae->nop+=2;break; + case CRC_E:___output(ae,0xCB);___output(ae,0x3+o);ae->nop+=2;break; + case CRC_H:___output(ae,0xCB);___output(ae,0x4+o);ae->nop+=2;break; + case CRC_L:___output(ae,0xCB);___output(ae,0x5+o);ae->nop+=2;break; + case CRC_MHL:___output(ae,0xCB);___output(ae,0x6+o);ae->nop+=4;break; + case CRC_A:___output(ae,0xCB);___output(ae,0x7+o);ae->nop+=2;break; + default: + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ___output(ae,0x6+o); + ae->nop+=7; + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD);___output(ae,0xCB); + PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8); + ___output(ae,0x6+o); + ae->nop+=7; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,reg8/(HL)/(IX+n)/(IY+n)\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + if (strncmp(ae->wl[ae->idx+2].w,"(IX",3)==0) { + ___output(ae,0xDD); + } else if (strncmp(ae->wl[ae->idx+2].w,"(IY",3)==0) { + ___output(ae,0xFD); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,(IX+n),reg8\n"); + } + ___output(ae,0xCB); + switch (GetCRC(ae->wl[ae->idx+3].w)) { + case CRC_B:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x0+o);ae->nop+=7;break; + case CRC_C:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x1+o);ae->nop+=7;break; + case CRC_D:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x2+o);ae->nop+=7;break; + case CRC_E:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x3+o);ae->nop+=7;break; + case CRC_H:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x4+o);ae->nop+=7;break; + case CRC_L:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x5+o);ae->nop+=7;break; + case CRC_A:PushExpression(ae,ae->idx+2,E_EXPRESSION_IV8);___output(ae,0x7+o);ae->nop+=7;break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,(IX+n),reg8\n"); + } + ae->idx+=3; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is SET n,reg8/(HL)/(IX+n)[,reg8]/(IY+n)[,reg8]\n"); + } + } +} + +void _DEFS(struct s_assenv *ae) { + int i,r,v; + if (ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is DEFS repeat,value or DEFS repeat\n"); + } else do { + ae->idx++; + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); /* doing FastTranslate but not a complete evaluation */ + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;i<r;i++) { + /* keep flexibility */ + PushExpression(ae,ae->idx+1,E_EXPRESSION_0V8); + ae->nop+=1; + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + v=0; + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;i<r;i++) { + ___output(ae,v); + ae->nop+=1; + } + } + } while (!ae->wl[ae->idx].t); +} + +void _DEFS_struct(struct s_assenv *ae) { + int i,r,v; + if (ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is DEFS repeat,value or DEFS repeat\n"); + } else do { + ae->idx++; + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;i<r;i++) { + ___output(ae,v); + ae->nop+=1; + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + r=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->codeadr,0); + v=0; + if (r<0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFS size must be greater or equal to zero\n"); + } + for (i=0;i<r;i++) { + ___output(ae,v); + ae->nop+=1; + } + } + } while (!ae->wl[ae->idx].t); +} + +void _STR(struct s_assenv *ae) { + unsigned char c; + int i,tquote; + + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'b':c='\b';break; + case 'v':c='\v';break; + case 'f':c='\f';break; + case '0':c='\0';break; + case 'r':c='\r';break; + case 'n':c='\n';break; + case 't':c='\t';break; + default:break; + } + if (ae->wl[ae->idx].w[i+1]!=tquote) { + ___output(ae,c); + } else { + ___output(ae,c|0x80); + } + } else { + /* charset conversion on the fly */ + if (ae->wl[ae->idx].w[i+1]!=tquote) { + ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); + } else { + ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]|0x80); + } + } + + i++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STR handle only quoted strings!\n"); + } + } while (ae->wl[ae->idx].t==0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STR needs one or more quotes parameters\n"); + } +} + +void _DEFR(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0VR); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFR needs one or more parameters\n"); + } + } +} +void _DEFR_struct(struct s_assenv *ae) { + unsigned char *rc; + double v; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + /* conversion des symboles connus */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + /* calcul de la valeur définitive de l'expression */ + v=ComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + /* conversion en réel Amsdos */ + rc=__internal_MakeAmsdosREAL(ae,v,0); + ___output(ae,rc[0]);___output(ae,rc[1]);___output(ae,rc[2]);___output(ae,rc[3]);___output(ae,rc[4]); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFR needs one or more parameters\n"); + } + } +} + +void _DEFB(struct s_assenv *ae) { + int i,tquote; + unsigned char c; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'b':___output(ae,'\b');break; + case 'v':___output(ae,'\v');break; + case 'f':___output(ae,'\f');break; + case '0':___output(ae,'\0');break; + case 'r':___output(ae,'\r');break; + case 'n':___output(ae,'\n');break; + case 't':___output(ae,'\t');break; + default: + ___output(ae,c); + ae->nop+=1; + } + } else { + /* charset conversion on the fly */ + ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); + ae->nop+=1; + } + i++; + } + } else { + PushExpression(ae,ae->idx,E_EXPRESSION_0V8); + ae->nop+=1; + } + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); + } + } +} +void _DEFB_struct(struct s_assenv *ae) { + int i,tquote; + unsigned char c; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'b':___output(ae,'\b');break; + case 'v':___output(ae,'\v');break; + case 'f':___output(ae,'\f');break; + case '0':___output(ae,'\0');break; + case 'r':___output(ae,'\r');break; + case 'n':___output(ae,'\n');break; + case 't':___output(ae,'\t');break; + default: + ___output(ae,c); + ae->nop+=1; + } + } else { + /* charset conversion on the fly */ + ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); + ae->nop+=1; + } + i++; + } + } else { + int v; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + ___output(ae,v); + ae->nop+=1; + } + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); + } + } +} + +void _DEFW(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V16); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); + } + } +} + +void _DEFW_struct(struct s_assenv *ae) { + int v; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + ___output(ae,v&0xFF);___output(ae,(v>>8)&0xFF); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); + } + } +} + +void _DEFI(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V32); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); + } + } +} + +void _DEFI_struct(struct s_assenv *ae) { + int v; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + v=RoundComputeExpressionCore(ae,ae->wl[ae->idx].w,ae->outputadr,0); + ___output(ae,v&0xFF);___output(ae,(v>>8)&0xFF);___output(ae,(v>>16)&0xFF);___output(ae,(v>>24)&0xFF); + } while (ae->wl[ae->idx].t==0); + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); + } + } +} + +void _DEFB_as80(struct s_assenv *ae) { + int i,tquote; + int modadr=0; + + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + if ((tquote=StringIsQuote(ae->wl[ae->idx].w))!=0) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') i++; + /* charset conversion on the fly */ + ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); + ae->nop+=1; + ae->codeadr--;modadr++; + i++; + } + } else { + PushExpression(ae,ae->idx,E_EXPRESSION_0V8); + ae->codeadr--;modadr++; + ae->nop+=1; + } + } while (ae->wl[ae->idx].t==0); + ae->codeadr+=modadr; + } else { + if (ae->getstruct) { + ___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFB needs one or more parameters\n"); + } + } +} + +void _DEFW_as80(struct s_assenv *ae) { + int modadr=0; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V16); + ae->codeadr-=2;modadr+=2; + } while (ae->wl[ae->idx].t==0); + ae->codeadr+=modadr; + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFW needs one or more parameters\n"); + } + } +} + +void _DEFI_as80(struct s_assenv *ae) { + int modadr=0; + if (!ae->wl[ae->idx].t) { + do { + ae->idx++; + PushExpression(ae,ae->idx,E_EXPRESSION_0V32); + ae->codeadr-=4;modadr+=4; + } while (ae->wl[ae->idx].t==0); + ae->codeadr+=modadr; + } else { + if (ae->getstruct) { + ___output(ae,0);___output(ae,0);___output(ae,0);___output(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFI needs one or more parameters\n"); + } + } +} +#if 0 +void _DEFSTR(struct s_assenv *ae) { + int i,tquote; + unsigned char c; + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (StringIsQuote(ae->wl[ae->idx+1].w) && StringIsQuote(ae->wl[ae->idx+2].w)) { + i=1; + while (ae->wl[ae->idx].w[i] && ae->wl[ae->idx].w[i]!=tquote) { + if (ae->wl[ae->idx].w[i]=='\\') { + i++; + /* no conversion on escaped chars */ + c=ae->wl[ae->idx].w[i]; + switch (c) { + case 'b':___output(ae,'\b');break; + case 'v':___output(ae,'\v');break; + case 'f':___output(ae,'\f');break; + case '0':___output(ae,'\0');break; + case 'r':___output(ae,'\r');break; + case 'n':___output(ae,'\n');break; + case 't':___output(ae,'\t');break; + default: + ___output(ae,c); + } + } else { + /* charset conversion on the fly */ + ___output(ae,ae->charset[(int)ae->wl[ae->idx].w[i]]); + } + i++; + } + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFSTR needs two parameters\n"); + } +} +#endif + +#undef FUNC +#define FUNC "Directive CORE" + +void __internal_UpdateLZBlockIfAny(struct s_assenv *ae) { + /* there was a crunched block opened in the previous bank */ + if (ae->lz>=0) { + //ae->lzsection[ae->ilz-1].iorgzone=ae->io-1; + //ae->lzsection[ae->ilz-1].ibank=ae->activebank; + } + ae->lz=-1; +} + + +void __AMSDOS(struct s_assenv *ae) { + ae->amsdos=1; +} + +void __internal_EXPORT(struct s_assenv *ae, int exportval) { + struct s_label *curlabel; + struct s_expr_dico *curdic; + int ialias,crc,freeflag; + char *localname; + + if (ae->wl[ae->idx].t) { + /* without parameter enable/disable export */ + ae->autorise_export=exportval; + } else while (!ae->wl[ae->idx].t) { + ae->idx++; + freeflag=0; + + /* local label */ + if (ae->wl[ae->idx].w[0]=='.' && ae->lastgloballabel) { + localname=MemMalloc(strlen(ae->wl[ae->idx].w)+1+ae->lastgloballabellen); + sprintf(localname,"%s%s",ae->lastgloballabel,ae->wl[ae->idx].w); + freeflag=1; + } else { + localname=ae->wl[ae->idx].w; + } + crc=GetCRC(localname); + + if ((curlabel=SearchLabel(ae,localname,crc))!=NULL) { + curlabel->autorise_export=exportval; + ae->label[curlabel->backidx].autorise_export=exportval; + } else { + if ((curdic=SearchDico(ae,ae->wl[ae->idx].w,crc))!=NULL) { + curdic->autorise_export=exportval; + } else { + if ((ialias=SearchAlias(ae,crc,ae->wl[ae->idx].w))!=-1) { + ae->alias[ialias].autorise_export=exportval; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"(E)NOEXPORT did not found [%s] in variables, labels or aliases\n",ae->wl[ae->idx].w); + } + } + } + if (freeflag) MemFree(localname); + } +} +void __NOEXPORT(struct s_assenv *ae) { + __internal_EXPORT(ae,0); +} +void __ENOEXPORT(struct s_assenv *ae) { + __internal_EXPORT(ae,1); +} + +void __BUILDZX(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDZX does not need a parameter\n"); + } + if (!ae->forcesnapshot && !ae->forcetape && !ae->forcecpr) { + ae->forcezx=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select ZX output when already in Amstrad cartridge/snapshot/tape output\n"); + } +} +void __BUILDCPR(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDCPR does not need a parameter\n"); + } + if (!ae->forcesnapshot && !ae->forcetape && !ae->forcezx) { + ae->forcecpr=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select Amstrad cartridge output when already in snapshot/tape output\n"); + } +} +void __BUILDSNA(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + if (strcmp(ae->wl[ae->idx+1].w,"V2")==0) { + ae->snapshot.version=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDSNA unrecognized option\n"); + } + } + if (!ae->forcecpr && !ae->forcetape && !ae->forcezx) { + ae->forcesnapshot=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select snapshot output when already in cartridge/tape output\n"); + } +} +void __BUILDTAPE(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BUILDTAPE does not need a parameter\n"); + } + if (!ae->forcesnapshot && !ae->forcecpr && !ae->forcezx) { + ae->forcetape=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot select tape output when already in snapshot/cartridge output\n"); + } +} + + +void __LZ4(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lz<ae->ilz) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=4; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZX7(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lz<ae->ilz) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=7; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZEXO(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + #ifdef NO_3RD_PARTIES + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot use 3rd parties cruncher with this version of RASM\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + FreeAssenv(ae); + exit(-5); + #endif + + if (ae->lz>=0 && ae->lz<ae->ilz) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=8; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZ48(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + if (ae->lz>=0 && ae->lz<ae->ilz) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); + FreeAssenv(ae); + exit(-5); + } + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=48; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZ49(struct s_assenv *ae) { + struct s_lz_section curlz; + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LZ directive does not need any parameter\n"); + return; + } + if (ae->lz>=0 && ae->lz<ae->ilz) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot start a new LZ section inside another one (%d)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ae->lz); + FreeAssenv(ae); + exit(-5); + } + + curlz.iw=ae->idx; + curlz.iorgzone=ae->io-1; + curlz.ibank=ae->activebank; + curlz.memstart=ae->outputadr; + curlz.memend=-1; + curlz.lzversion=49; + ae->lz=ae->ilz; + ObjectArrayAddDynamicValueConcat((void**)&ae->lzsection,&ae->ilz,&ae->mlz,&curlz,sizeof(curlz)); +} +void __LZCLOSE(struct s_assenv *ae) { + if (!ae->ilz || ae->lz==-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot close LZ section as it wasn't opened\n"); + return; + } + + ae->lzsection[ae->ilz-1].memend=ae->outputadr; + ae->lzsection[ae->ilz-1].ilabel=ae->il; + ae->lzsection[ae->ilz-1].iexpr=ae->ie; + //ae->lz=ae->ilz; + ae->lz=-1; +} + +void __LIMIT(struct s_assenv *ae) { + if (ae->wl[ae->idx+1].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ___output_set_limit(ae,RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->outputadr,0,0)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LIMIT directive need one integer parameter\n"); + } +} +void OverWriteCheck(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "OverWriteCheck" + + int i,j; + + /* overwrite checking */ + i=ae->io-1; { + if (ae->orgzone[i].memstart!=ae->orgzone[i].memend) { + for (j=0;j<ae->io-1;j++) { + if (ae->orgzone[j].memstart!=ae->orgzone[j].memend && !ae->orgzone[j].nocode) { + if (ae->orgzone[i].ibank==ae->orgzone[j].ibank) { + if ((ae->orgzone[i].memstart>=ae->orgzone[j].memstart && ae->orgzone[i].memstart<ae->orgzone[j].memend) + || (ae->orgzone[i].memend>ae->orgzone[j].memstart && ae->orgzone[i].memend<ae->orgzone[j].memend) + || (ae->orgzone[i].memstart<=ae->orgzone[j].memstart && ae->orgzone[i].memend>=ae->orgzone[j].memend)) { + ae->idx--; + if (ae->orgzone[j].protect) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PROTECTED section error [%s] L%d [#%04X-#%04X-B%d] with [%s] L%d [#%04X/#%04X]\n",ae->filename[ae->orgzone[j].ifile],ae->orgzone[j].iline,ae->orgzone[j].memstart,ae->orgzone[j].memend,ae->orgzone[j].ibank<32?ae->orgzone[j].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline,ae->orgzone[i].memstart,ae->orgzone[i].memend); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Assembling overwrite [%s] L%d [#%04X-#%04X-B%d] with [%s] L%d [#%04X/#%04X]\n",ae->filename[ae->orgzone[j].ifile],ae->orgzone[j].iline,ae->orgzone[j].memstart,ae->orgzone[j].memend,ae->orgzone[j].ibank<32?ae->orgzone[j].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline,ae->orgzone[i].memstart,ae->orgzone[i].memend); + } + i=j=ae->io; + break; + } + } + } + } + } + } +} + +void ___new_memory_space(struct s_assenv *ae) +{ + #undef FUNC + #define FUNC "___new_memory_space" + + unsigned char *mem; + struct s_orgzone orgzone={0}; + + __internal_UpdateLZBlockIfAny(ae); + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + if (ae->lz>=0) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new memory space directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + __LZCLOSE(ae); + } + ae->activebank=ae->nbbank; + mem=MemMalloc(65536); + memset(mem,0,65536); + ObjectArrayAddDynamicValueConcat((void**)&ae->mem,&ae->nbbank,&ae->maxbank,&mem,sizeof(mem)); + + ae->outputadr=0; + ae->codeadr=0; + orgzone.memstart=0; + orgzone.ibank=ae->activebank; + orgzone.nocode=ae->nocode=0; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + + OverWriteCheck(ae); +} + +void __BANK(struct s_assenv *ae) { + struct s_orgzone orgzone={0}; + int oldcode=0,oldoutput=0; + int i; + __internal_UpdateLZBlockIfAny(ae); + + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + /* without parameter, create a new empty space */ + if (ae->wl[ae->idx].t==1) { + ___new_memory_space(ae); + return; + } + + ae->bankmode=1; + if (!ae->forcecpr && !ae->forcesnapshot && !ae->forcezx) ae->forcecpr=1; + + if (ae->wl[ae->idx+1].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->activebank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + if (ae->forcecpr && (ae->activebank<0 || ae->activebank>31)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 31 in cartridge mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + FreeAssenv(ae); + exit(2); + } else if (ae->forcezx && (ae->activebank<0 || ae->activebank>7)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 7 in ZX Spectrum mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + FreeAssenv(ae); + exit(2); + } else if (ae->forcesnapshot && (ae->activebank<0 || ae->activebank>=260)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank selection must be from 0 to 259 in snapshot mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + FreeAssenv(ae); + exit(2); + } + /* bankset control */ + if (ae->forcesnapshot && ae->bankset[ae->activebank/4]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot BANK %d was already select by a previous BANKSET %d\n",ae->activebank,(int)ae->activebank/4); + ae->idx++; + return; + } else { + ae->bankused[ae->activebank]=1; + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANK directive need one integer parameter\n"); + return; + } + if (ae->lz>=0) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new BANK directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + __LZCLOSE(ae); + } + + /* try to get an old ORG settings backward */ + for (i=ae->io-1;i>=0;i--) { + if (ae->orgzone[i].ibank==ae->activebank) { + oldcode=ae->orgzone[i].memend; + oldoutput=ae->orgzone[i].memend; + break; + } + } + ae->outputadr=oldoutput; + ae->codeadr=oldcode; + orgzone.memstart=ae->outputadr; + /* legacy */ + orgzone.ibank=ae->activebank; + orgzone.nocode=ae->nocode=0; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + + OverWriteCheck(ae); +} + +void __BANKSET(struct s_assenv *ae) { + struct s_orgzone orgzone={0}; + int ibank; + + __internal_UpdateLZBlockIfAny(ae); + + if (!ae->forcesnapshot && !ae->forcecpr && !ae->forcezx) ae->forcesnapshot=1; + if (!ae->forcesnapshot) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANKSET directive is specific to snapshot output\n"); + return; + } + + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + ae->bankmode=1; + + if (ae->wl[ae->idx+1].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->activebank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->activebank*=4; + if (ae->forcesnapshot && (ae->activebank<0 || ae->activebank>=260)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"FATAL - Bank set selection must be from 0 to 64 in snapshot mode\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + FreeAssenv(ae); + exit(2); + } + /* control */ + ibank=ae->activebank; + if (ae->bankused[ibank] || ae->bankused[ibank+1]|| ae->bankused[ibank+2]|| ae->bankused[ibank+3]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot BANKSET because bank %d was already selected in single page mode\n",ibank); + ae->idx++; + return; + } else { + ae->bankset[ae->activebank/4]=1; /* pas très heureux mais bon... */ + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BANKSET directive need one integer parameter\n"); + return; + } + if (ae->lz>=0) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: LZ section wasn't closed before a new BANKSET directive\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + __LZCLOSE(ae); + } + + ae->outputadr=0; + ae->codeadr=0; + orgzone.memstart=0; + orgzone.ibank=ae->activebank; + orgzone.nocode=ae->nocode=0; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + + OverWriteCheck(ae); +} + + +void __NameBANK(struct s_assenv *ae) { + int ibank; + + ae->bankmode=1; + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + if (!StringIsQuote(ae->wl[ae->idx+2].w)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Syntax is NAMEBANK <bank number>,'<string>'\n"); + } else { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ibank=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + if (ibank<0 || ibank>=BANK_MAX_NUMBER) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NAMEBANK selection must be from 0 to %d\n",BANK_MAX_NUMBER); + } else { + ae->iwnamebank[ibank]=ae->idx+2; + } + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NAMEBANK directive need one integer parameter and a string\n"); + } +} + +/*** + Winape little compatibility for CPR writing! +*/ +void __WRITE(struct s_assenv *ae) { + int ok=0; + int lower=-1,upper=-1,bank=-1; + + if (!ae->wl[ae->idx].t && strcmp(ae->wl[ae->idx+1].w,"DIRECT")==0 && !ae->wl[ae->idx+1].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + lower=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); + upper=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->codeadr,0,0); + } + if (!ae->wl[ae->idx+3].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+4].w,0); + bank=RoundComputeExpression(ae,ae->wl[ae->idx+4].w,ae->codeadr,0,0); + } + + if (ae->maxam) { + if (lower==65535) lower=-1; + if (upper==65535) upper=-1; + if (bank==65535) bank=-1; + } + + if (lower!=-1) { + if (lower>=0 && lower<8) { + ae->idx+=1; + __BANK(ae); + ok=1; + } else { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT lower ROM ignored (value %d out of bounds 0-7)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,lower); + } + } else if (upper!=-1) { + if (upper>=0 && ((ae->forcecpr && upper<32) || (ae->forcesnapshot && upper<BANK_MAX_NUMBER))) { + ae->idx+=2; + __BANK(ae); + ok=1; + } else { + if (!ae->forcecpr && !ae->forcesnapshot) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT select a ROM without cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + } else { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: WRITE DIRECT upper ROM ignored (value %d out of bounds 0-31)\n",GetCurrentFile(ae),ae->wl[ae->idx].l,upper); + } + } + } else if (bank!=-1) { + /* selection de bank on ouvre un nouvel espace */ + } else { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: meaningless WRITE DIRECT\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + } + } + while (!ae->wl[ae->idx].t) ae->idx++; + if (!ok) { + ___new_memory_space(ae); + } +} +void __CHARSET(struct s_assenv *ae) { + int i,s,e,v,tquote; + + if (ae->wl[ae->idx].t==1) { + /* reinit charset */ + for (i=0;i<256;i++) + ae->charset[i]=i; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + /* string,value | byte,value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + v=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); + if (ae->wl[ae->idx+1].w[0]=='\'' || ae->wl[ae->idx+1].w[0]=='"') { + tquote=ae->wl[ae->idx+1].w[0]; + if (ae->wl[ae->idx+1].w[strlen(ae->wl[ae->idx+1].w)-1]==tquote) { + i=1; + while (ae->wl[ae->idx+1].w[i] && ae->wl[ae->idx+1].w[i]!=tquote) { + if (ae->wl[ae->idx+1].w[i]=='\\') i++; + ae->charset[(int)ae->wl[ae->idx+1].w[i]]=(unsigned char)v++; + i++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET string,value has invalid quote!\n"); + } + } else { + i=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + if (i>=0 && i<256) { + ae->charset[i]=(unsigned char)v; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET byte value must be 0-255\n"); + } + } + ae->idx+=2; + } else if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && !ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t==1) { + /* start,end,value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); + s=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + e=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->codeadr,0,0); + v=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->codeadr,0,0); + ae->idx+=3; + if (s<=e && s>=0 && e<256) { + for (i=s;i<=e;i++) { + ae->charset[i]=(unsigned char)v++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET winape directive wrong interval value\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CHARSET winape directive wrong parameter count\n"); + } +} + +void __MACRO(struct s_assenv *ae) { + struct s_macro curmacro={0}; + char *referentfilename,*zeparam; + int refidx,idx,getparam=1; + struct s_wordlist curwl; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t!=2) { + /* get the name */ + curmacro.mnemo=ae->wl[ae->idx+1].w; + curmacro.crc=GetCRC(curmacro.mnemo); + if (ae->wl[ae->idx+1].t) { + getparam=0; + } + /* overload forbidden */ + if (SearchMacro(ae,curmacro.crc,curmacro.mnemo)>=0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro already defined with this name\n"); + } + idx=ae->idx+2; + while (ae->wl[idx].t!=2 && (GetCRC(ae->wl[idx].w)!=CRC_MEND || strcmp(ae->wl[idx].w,"MEND")!=0) && (GetCRC(ae->wl[idx].w)!=CRC_ENDM || strcmp(ae->wl[idx].w,"ENDM")!=0)) { + if (GetCRC(ae->wl[idx].w)==CRC_MACRO || strcmp(ae->wl[idx].w,"MACRO")==0) { + /* inception interdite */ + referentfilename=GetCurrentFile(ae); + refidx=ae->idx; + ae->idx=idx; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"You cannot define a macro inside another one (MACRO %s in [%s] L%d)\n",ae->wl[refidx+1].w,referentfilename,ae->wl[refidx].l); + __STOP(ae); + } + if (getparam) { + /* on prepare les parametres au remplacement */ + zeparam=MemMalloc(strlen(ae->wl[idx].w)+3); + if (ae->as80) { + sprintf(zeparam,"%s",ae->wl[idx].w); + } else { + sprintf(zeparam,"{%s}",ae->wl[idx].w); + } + curmacro.nbparam++; + curmacro.param=MemRealloc(curmacro.param,curmacro.nbparam*sizeof(char **)); + curmacro.param[curmacro.nbparam-1]=zeparam; + if (ae->wl[idx].t) { + /* duplicate parameters without brackets MUST be an OPTION */ + getparam=0; + } + } else { + /* copie la liste de mots */ + curwl=ae->wl[idx]; + ObjectArrayAddDynamicValueConcat((void **)&curmacro.wc,&curmacro.nbword,&curmacro.maxword,&curwl,sizeof(struct s_wordlist)); + } + idx++; + } + if (ae->wl[idx].t==2) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Macro was not closed\n"); + } + ObjectArrayAddDynamicValueConcat((void**)&ae->macro,&ae->imacro,&ae->mmacro,&curmacro,sizeof(curmacro)); + /* le quicksort n'est pas optimal mais on n'est pas supposé en créer des milliers */ + qsort(ae->macro,ae->imacro,sizeof(struct s_macro),cmpmacros); + + /* ajustement des mots lus */ + if (ae->wl[idx].t==2) idx--; + ae->idx=idx; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO definition need at least one parameter\n"); + } +} + +struct s_wordlist *__MACRO_EXECUTE(struct s_assenv *ae, int imacro) { + struct s_wordlist *cpybackup; + int nbparam=0,idx,i,j,idad; + int ifile,iline,iu,lenparam; + double v; + struct s_macro_position curmacropos={0}; + char *zeparam=NULL,*txtparamlist; + int reload=0; + + idx=ae->idx; + while (!ae->wl[idx].t) { + nbparam++; + idx++; + } + + /* hack to secure macro without parameters with void argument */ + if (!ae->macro[imacro].nbparam) { + if (nbparam) { + if (nbparam==1 && strcmp(ae->wl[ae->idx+1].w,"(VOID)")==0) { + nbparam=0; + reload=1; + } + } else { + if (ae->macrovoid) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] used without (void) and option -void used!\n",ae->macro[imacro].mnemo); + while (!ae->wl[ae->idx].t) { + ae->idx++; + } + ae->idx++; + } + } + } + /* macro must avoid extra params! */ + + /* cannot VOID a macro with parameters! */ + if (ae->macro[imacro].nbparam && strcmp(ae->wl[ae->idx+1].w,"(VOID)")==0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] has %d parameter%s\n",ae->macro[imacro].mnemo,ae->macro[imacro].nbparam,ae->macro[imacro].nbparam>1?"s":""); + while (!ae->wl[ae->idx].t) { + ae->idx++; + } + ae->idx++; + } else { + if (nbparam!=ae->macro[imacro].nbparam) { + lenparam=1; // macro without parameters! + for (i=0;i<ae->macro[imacro].nbparam;i++) { + lenparam+=strlen(ae->macro[imacro].param[i])+3; + } + txtparamlist=MemMalloc(lenparam); + txtparamlist[0]=0; + for (i=0;i<ae->macro[imacro].nbparam;i++) { + strcat(txtparamlist,ae->macro[imacro].param[i]); + strcat(txtparamlist," "); + } + + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MACRO [%s] was defined with %d parameter%s %s\n",ae->macro[imacro].mnemo,ae->macro[imacro].nbparam,ae->macro[imacro].nbparam>1?"s":"",txtparamlist); + while (!ae->wl[ae->idx].t) { + ae->idx++; + } + ae->idx++; + } else { + /* free macro call as we will overwrite it */ + MemFree(ae->wl[ae->idx].w); + /* is there a void to free? */ + if (reload) { + MemFree(ae->wl[ae->idx+1].w); + } + /* eval parameters? */ + for (i=0;i<nbparam;i++) { + if (strncmp(ae->wl[ae->idx+1+i].w,"{EVAL}",6)==0) { + /* parametre entre chevrons, il faut l'interpreter d'abord */ + zeparam=TxtStrDup(ae->wl[ae->idx+1+i].w+6); + ExpressionFastTranslate(ae,&zeparam,1); + v=ComputeExpressionCore(ae,zeparam,ae->codeadr,0); + MemFree(zeparam); + zeparam=MemMalloc(32); + snprintf(zeparam,31,"%lf",v); + zeparam[31]=0; + MemFree(ae->wl[ae->idx+1+i].w); + ae->wl[ae->idx+1+i].w=zeparam; + } + } + /* backup parameters */ + cpybackup=MemMalloc((nbparam+1)*sizeof(struct s_wordlist)); + for (i=0;i<nbparam;i++) { + cpybackup[i]=ae->wl[ae->idx+1+i]; + } + /* insert macro position */ + curmacropos.start=ae->idx; + curmacropos.end=ae->idx+ae->macro[imacro].nbword; + curmacropos.value=ae->macrocounter; + ObjectArrayAddDynamicValueConcat((void**)&ae->macropos,&ae->imacropos,&ae->mmacropos,&curmacropos,sizeof(curmacropos)); + + /* are we in a repeat/while block? */ + for (iu=0;iu<ae->ir;iu++) if (ae->repeat[iu].maxim<ae->imacropos) ae->repeat[iu].maxim=ae->imacropos; + for (iu=0;iu<ae->iw;iu++) if (ae->whilewend[iu].maxim<ae->imacropos) ae->whilewend[iu].maxim=ae->imacropos; + + /* update daddy macropos */ + for (idad=0;idad<ae->imacropos-1;idad++) { + if (ae->macropos[idad].end>curmacropos.start) { + ae->macropos[idad].end+=ae->macro[imacro].nbword-1-nbparam-reload; /* coz la macro compte un mot! */ + } + } + + #if 0 + for (idad=0;idad<ae->imacropos;idad++) { + printf("macropos[%d]=%d -> %d\n",idad,ae->macropos[idad].start,ae->macropos[idad].end); + } + #endif + /* insert at macro position and replace macro+parameters */ + if (ae->macro[imacro].nbword>1+nbparam+reload) { + ae->nbword+=ae->macro[imacro].nbword-1-nbparam-reload; + ae->wl=MemRealloc(ae->wl,ae->nbword*sizeof(struct s_wordlist)); + } else { + /* si on réduit pas de realloc pour ne pas perdre de donnees */ + ae->nbword+=ae->macro[imacro].nbword-1-nbparam-reload; + } + iline=ae->wl[ae->idx].l; + ifile=ae->wl[ae->idx].ifile; + MemMove(&ae->wl[ae->idx+ae->macro[imacro].nbword],&ae->wl[ae->idx+reload+nbparam+1],(ae->nbword-ae->idx-ae->macro[imacro].nbword)*sizeof(struct s_wordlist)); + + for (i=0;i<ae->macro[imacro].nbword;i++) { + ae->wl[i+ae->idx].w=TxtStrDup(ae->macro[imacro].wc[i].w); + ae->wl[i+ae->idx].l=iline; + ae->wl[i+ae->idx].ifile=ifile; + /* @@@sujet a evolution, ou double controle */ + ae->wl[i+ae->idx].t=ae->macro[imacro].wc[i].t; + ae->wl[i+ae->idx].e=ae->macro[imacro].wc[i].e; + } + /* replace */ + idx=ae->idx; + for (i=0;i<nbparam;i++) { + for (j=idx;j<idx+ae->macro[imacro].nbword;j++) { + /* tags in upper case for replacement in quotes */ + if (StringIsQuote(ae->wl[j].w)) { + int lm,touched; + for (lm=touched=0;ae->wl[j].w[lm];lm++) { + if (ae->wl[j].w[lm]=='{') touched++; else if (ae->wl[j].w[lm]=='}') touched--; else if (touched) ae->wl[j].w[lm]=toupper(ae->wl[j].w[lm]); + } + } + ae->wl[j].w=TxtReplace(ae->wl[j].w,ae->macro[imacro].param[i],cpybackup[i].w,0); + } + MemFree(cpybackup[i].w); + } + MemFree(cpybackup); + /* macro replaced, need to rollback index */ + //ae->idx--; + } + } + /* a chaque appel de macro on incremente le compteur pour les labels locaux */ + ae->macrocounter++; + + return ae->wl; +} + +/* + ticker start, <var> + ticker stop, <var> +*/ +void __TICKER(struct s_assenv *ae) { + struct s_expr_dico *tvar; + struct s_ticker ticker; + int crc,i; + + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + crc=GetCRC(ae->wl[ae->idx+2].w); + + if (strcmp(ae->wl[ae->idx+1].w,"START")==0) { + /* is there already a counter? */ + for (i=0;i<ae->iticker;i++) { + if (ae->ticker[i].crc==crc && strcmp(ae->wl[ae->idx+2].w,ae->ticker[i].varname)==0) { + break; + } + } + if (i==ae->iticker) { + ticker.varname=TxtStrDup(ae->wl[ae->idx+2].w); + ticker.crc=crc; + ObjectArrayAddDynamicValueConcat((void **)&ae->ticker,&ae->iticker,&ae->mticker,&ticker,sizeof(struct s_ticker)); + } + ae->ticker[i].nopstart=ae->nop; + } else if (strcmp(ae->wl[ae->idx+1].w,"STOP")==0) { + for (i=0;i<ae->iticker;i++) { + if (ae->ticker[i].crc==crc && strcmp(ae->wl[ae->idx+2].w,ae->ticker[i].varname)==0) { + break; + } + } + if (i<ae->iticker) { + /* set var */ + if ((tvar=SearchDico(ae,ae->wl[ae->idx+2].w,crc))!=NULL) { + /* compute nop count */ + tvar->v=ae->nop-ae->ticker[i].nopstart; + } else { + /* create var with nop count */ + ExpressionSetDicoVar(ae,ae->wl[ae->idx+2].w,ae->nop-ae->ticker[i].nopstart); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"TICKER not found\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is TICKER start/stop,<variable>\n"); + } + ae->idx+=2; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is TICKER start/stop,<variable>\n"); + } +} + +void __LET(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ae->idx++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx].w,0); + RoundComputeExpression(ae,ae->wl[ae->idx].w,ae->codeadr,0,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LET useless winape directive need one expression\n"); + } +} + +void __RUN(struct s_assenv *ae) { + int ramconf=0xC0; + + if (!ae->wl[ae->idx].t) { + ae->current_run_idx=ae->idx+1; + if (ae->forcezx) { + if (!ae->wl[ae->idx].t) { + PushExpression(ae,ae->idx+1,E_EXPRESSION_ZXRUN); // delayed RUN value + PushExpression(ae,ae->idx+2,E_EXPRESSION_ZXSTACK); // delayed STACK value + ae->idx+=2; + } else { + ae->idx++; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN <adress>,<stack> (ZX mode)\n"); + } + } else { + PushExpression(ae,ae->idx+1,E_EXPRESSION_RUN); // delayed RUN value + ae->idx++; + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ramconf=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + if (ramconf<0xC0 || ramconf>0xFF) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: ram configuration out of bound %X forced to #C0\n",GetCurrentFile(ae),ae->wl[ae->idx].l,ramconf); + } + } + } + } else { + if (ae->forcezx) MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN <adress>,<stack> (ZX mode)\n"); + else MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is RUN <adress>[,<ppi>]\n"); + } + ae->snapshot.ramconfiguration=ramconf; + if (ae->rundefined && !ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: run adress redefinition\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + ae->rundefined=1; +} +void __BREAKPOINT(struct s_assenv *ae) { + struct s_breakpoint breakpoint={0}; + + if (ae->activebank>3) breakpoint.bank=1; + if (ae->wl[ae->idx].t) { + breakpoint.address=ae->codeadr; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } else if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + breakpoint.address=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is BREAKPOINT [adress]\n"); + } +} +void __SETCPC(struct s_assenv *ae) { + int mycpc; + + if (!ae->forcecpr) { + ae->forcesnapshot=1; + } else { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: Cannot SETCPC when already in cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + } + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + mycpc=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + switch (mycpc) { + case 0: + case 1: + case 2: + case 4: + case 5: + case 6: + ae->snapshot.CPCType=mycpc; + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCPC directive has wrong value (0,1,2,4,5,6 only)\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCPC directive need one integer parameter\n"); + } +} +void __SETCRTC(struct s_assenv *ae) { + int mycrtc; + + if (!ae->forcecpr) { + ae->forcesnapshot=1; + } else { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: Cannot SETCRTC when already in cartridge output\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + } + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + mycrtc=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCRTC directive need one integer parameter\n"); + } + switch (mycrtc) { + case 0: + case 1: + case 2: + case 3: + case 4: + ae->snapshot.crtcstate.model=mycrtc; + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SETCRTC directive has wrong value (0,1,2,3,4 only)\n"); + } +} + + +void __LIST(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"LIST winape directive do not need parameter\n"); + } +} +void __NOLIST(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOLIST winape directive do not need parameter\n"); + } +} + +void __BRK(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BRK winape directive do not need parameter\n"); + } +} + +void __STOP(struct s_assenv *ae) { + rasm_printf(ae,"[%s:%d] STOP assembling requested\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + while (ae->wl[ae->idx].t!=2) ae->idx++; + ae->idx--; + ae->stop=1; +} + +void __PRINT(struct s_assenv *ae) { + while (ae->wl[ae->idx].t!=1) { + if (!StringIsQuote(ae->wl[ae->idx+1].w)) { + char *string2print=NULL; + int hex=0,bin=0,entier=0; + + if (strncmp(ae->wl[ae->idx+1].w,"{HEX}",5)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); + hex=1; + } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX2}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + hex=2; + } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX4}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + hex=4; + } else if (strncmp(ae->wl[ae->idx+1].w,"{HEX8}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + hex=8; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN}",5)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); + bin=1; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN8}",6)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+6); + bin=8; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN16}",7)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+7); + bin=16; + } else if (strncmp(ae->wl[ae->idx+1].w,"{BIN32}",7)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+7); + bin=32; + } else if (strncmp(ae->wl[ae->idx+1].w,"{INT}",5)==0) { + string2print=TxtStrDup(ae->wl[ae->idx+1].w+5); + entier=1; + } else { + string2print=TxtStrDup(ae->wl[ae->idx+1].w); + } + + ExpressionFastTranslate(ae,&string2print,1); + if (hex) { + int zv; + zv=RoundComputeExpressionCore(ae,string2print,ae->codeadr,0); + switch (hex) { + case 1: + if (zv&0xFFFFFF00) { + if (zv&0xFFFF0000) { + rasm_printf(ae,"#%-8.08X ",zv); + } else { + rasm_printf(ae,"#%-4.04X ",zv); + } + } else { + rasm_printf(ae,"#%-2.02X ",zv); + } + break; + case 2:rasm_printf(ae,"#%-2.02X ",zv);break; + case 4:rasm_printf(ae,"#%-4.04X ",zv);break; + case 8:rasm_printf(ae,"#%-8.08X ",zv);break; + } + } else if (bin) { + int zv,d; + zv=RoundComputeExpressionCore(ae,string2print,ae->codeadr,0); + /* remove useless sign bits */ + if (bin<32 && (zv&0xFFFF0000)==0xFFFF0000) { + zv&=0xFFFF; + } + switch (bin) { + case 1:if (zv&0xFF00) d=15; else d=7;break; + case 8:d=7;break; + case 16:d=15;break; + case 32:d=31;break; + } + rasm_printf(ae,"%%"); + for (;d>=0;d--) { + if ((zv>>d)&1) rasm_printf(ae,"1"); else rasm_printf(ae,"0"); + } + rasm_printf(ae," "); + } else if (entier) { + rasm_printf(ae,"%d ",(int)RoundComputeExpressionCore(ae,string2print,ae->codeadr,0)); + } else { + rasm_printf(ae,"%.2lf ",ComputeExpressionCore(ae,string2print,ae->codeadr,0)); + } + MemFree(string2print); + } else { + char *varbuffer; + int lm,touched; + lm=strlen(ae->wl[ae->idx+1].w)-2; + if (lm) { + varbuffer=MemMalloc(lm+2); + sprintf(varbuffer,"%-*.*s ",lm,lm,ae->wl[ae->idx+1].w+1); + /* need to upper case tags */ + for (lm=touched=0;varbuffer[lm];lm++) { + if (varbuffer[lm]=='{') touched++; else if (varbuffer[lm]=='}') touched--; else if (touched) varbuffer[lm]=toupper(varbuffer[lm]); + } + /* translate tag will check tag consistency */ + varbuffer=TranslateTag(ae,varbuffer,&touched,1,E_TAGOPTION_REMOVESPACE); + varbuffer=TxtReplace(varbuffer,"\\b","\b",0); + varbuffer=TxtReplace(varbuffer,"\\v","\v",0); + varbuffer=TxtReplace(varbuffer,"\\f","\f",0); + varbuffer=TxtReplace(varbuffer,"\\r","\r",0); + varbuffer=TxtReplace(varbuffer,"\\n","\n",0); + varbuffer=TxtReplace(varbuffer,"\\t","\t",0); + rasm_printf(ae,"%s ",varbuffer); + MemFree(varbuffer); + } + } + ae->idx++; + } + rasm_printf(ae,"\n"); +} + +void __FAIL(struct s_assenv *ae) { + __PRINT(ae); + __STOP(ae); + MaxError(ae); +} + +void __ALIGN(struct s_assenv *ae) { + int aval,ifill=-1; + + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + aval=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + /* align with fill ? */ + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ifill=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,0); + ae->idx++; + if (ifill<0 || ifill>255) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN fill value must be 0 to 255\n"); + ifill=0; + } + } + + if (aval<1 || aval>65535) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN boundary must be greater than zero and lower than 65536\n"); + aval=1; + } + + /* touch codeadr only if adress is misaligned */ + if (ae->codeadr%aval) { + if (ifill==-1) { + /* virtual ALIGN is moving outputadr the same value as codeadr move */ + ae->outputadr=ae->outputadr-(ae->codeadr%aval)+aval; + ae->codeadr=ae->codeadr-(ae->codeadr%aval)+aval; + } else { + /* physical ALIGN fill bytes */ + while (ae->codeadr%aval) { + ___output(ae,ifill); + ae->nop+=1; + } + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ALIGN <boundary>[,fill] directive need one or two integers parameters\n"); + } +} + +void ___internal_skip_loop_block(struct s_assenv *ae, int eloopstyle) { + int *loopstyle=NULL; + int iloop=0,mloop=0; + int cidx; + + cidx=ae->idx+2; + + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,eloopstyle); + /* look for WEND */ + while (iloop) { + if (strcmp(ae->wl[cidx].w,"REPEAT")==0) { + if (ae->wl[cidx].t) { + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_REPEATUNTIL); + } else if (ae->wl[cidx+1].t) { + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_REPEATN); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid REPEAT syntax\n"); + } + } else if (strcmp(ae->wl[cidx].w,"WHILE")==0) { + if (!ae->wl[cidx].t && ae->wl[cidx+1].t) { + IntArrayAddDynamicValueConcat(&loopstyle,&iloop,&mloop,E_LOOPSTYLE_WHILE); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Invalid WHILE syntax\n"); + } + } else if (strcmp(ae->wl[cidx].w,"WEND")==0) { + iloop--; + if (iloop<0) { + iloop=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encountered that was not expected\n"); + } else if (loopstyle[iloop]!=E_LOOPSTYLE_WHILE) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATN?"REND":"UNTIL"); + } + } else if (strcmp(ae->wl[cidx].w,"REND")==0) { + iloop--; + if (iloop<0) { + iloop=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encountered that was not expected\n"); + } else if (loopstyle[iloop]!=E_LOOPSTYLE_REPEATN) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATUNTIL?"UNTIL":"WEND"); + } + } else if (strcmp(ae->wl[cidx].w,"UNTIL")==0) { + iloop--; + if (iloop<0) { + iloop=0; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encountered that was not expected\n"); + } else if (loopstyle[iloop]!=E_LOOPSTYLE_REPEATUNTIL) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encountered but expecting %s\n",loopstyle[iloop]==E_LOOPSTYLE_REPEATN?"REND":"WEND"); + } + } + while (!ae->wl[cidx].t) cidx++; + cidx++; + } + MemFree(loopstyle); + ae->idx=cidx-1; +} + +void __WHILE(struct s_assenv *ae) { + struct s_whilewend whilewend={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + if (!ComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,2)) { + /* skip while block */ + ___internal_skip_loop_block(ae,E_LOOPSTYLE_WHILE); + return; + } else { + ae->idx++; + whilewend.start=ae->idx; + whilewend.cpt=0; + whilewend.value=ae->whilecounter; + whilewend.maxim=ae->imacropos; + whilewend.while_counter=1; + ae->whilecounter++; + /* pour gérer les macros situés dans le while précedent après un repeat/while courant */ + if (ae->iw) whilewend.maxim=ae->whilewend[ae->iw-1].maxim; + if (ae->ir && ae->repeat[ae->ir-1].maxim>whilewend.maxim) whilewend.maxim=ae->repeat[ae->ir-1].maxim; + ObjectArrayAddDynamicValueConcat((void**)&ae->whilewend,&ae->iw,&ae->mw,&whilewend,sizeof(whilewend)); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is WHILE <expression>\n"); + } +} +void __WEND(struct s_assenv *ae) { + if (ae->iw>0) { + if (ae->wl[ae->idx].t==1) { + if (ComputeExpression(ae,ae->wl[ae->whilewend[ae->iw-1].start].w,ae->codeadr,0,2)) { + if (ae->whilewend[ae->iw-1].while_counter>65536) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Bypass infinite WHILE loop\n"); + ae->iw--; + /* refresh macro check index */ + if (ae->iw) ae->imacropos=ae->whilewend[ae->iw-1].maxim; + } else { + ae->whilewend[ae->iw-1].cpt++; /* for local label */ + ae->whilewend[ae->iw-1].while_counter++; + ae->idx=ae->whilewend[ae->iw-1].start; + /* refresh macro check index */ + ae->imacropos=ae->whilewend[ae->iw-1].maxim; + } + } else { + ae->iw--; + /* refresh macro check index */ + if (ae->iw) ae->imacropos=ae->whilewend[ae->iw-1].maxim; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WEND encounter whereas there is no referent WHILE\n"); + } +} + +void __REPEAT(struct s_assenv *ae) { + struct s_repeat currepeat={0}; + struct s_expr_dico *rvar; + int *loopstyle; + int iloop,mloop; + int cidx,crc; + + if (ae->wl[ae->idx+1].t!=2) { + if (ae->wl[ae->idx].t==0) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + currepeat.cpt=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); + if (!currepeat.cpt) { + /* skip repeat block */ + ___internal_skip_loop_block(ae,E_LOOPSTYLE_REPEATN); + return; + } else if (currepeat.cpt<1 || currepeat.cpt>65536) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Repeat value (%d) must be from 1 to 65535. Skipping block\n",currepeat.cpt); + ___internal_skip_loop_block(ae,E_LOOPSTYLE_REPEATN); + return; + } + ae->idx++; + currepeat.start=ae->idx; + if (ae->wl[ae->idx].t==0) { + ae->idx++; + if (ae->wl[ae->idx].t==1) { + /* la variable peut exister -> OK */ + crc=GetCRC(ae->wl[ae->idx].w); + if ((rvar=SearchDico(ae,ae->wl[ae->idx].w,crc))!=NULL) { + rvar->v=1; + } else { + /* mais ne peut être un label ou un alias */ + ExpressionSetDicoVar(ae,ae->wl[ae->idx].w, 1); + } + currepeat.repeatvar=ae->wl[ae->idx].w; + currepeat.repeatcrc=crc; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"extended syntax is REPEAT <n>,<var>\n"); + } + } + } else { + currepeat.start=ae->idx; + currepeat.cpt=-1; + } + currepeat.value=ae->repeatcounter; + currepeat.repeat_counter=1; + ae->repeatcounter++; + /* pour gérer les macros situés dans le repeat précedent après le repeat courant */ + if (ae->ir) currepeat.maxim=ae->repeat[ae->ir-1].maxim; + if (ae->iw && ae->whilewend[ae->iw-1].maxim>currepeat.maxim) currepeat.maxim=ae->whilewend[ae->iw-1].maxim; + if (ae->imacropos>currepeat.maxim) currepeat.maxim=ae->imacropos; + ObjectArrayAddDynamicValueConcat((void**)&ae->repeat,&ae->ir,&ae->mr,&currepeat,sizeof(currepeat)); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"wrong REPEAT usage\n"); + } +} + +void __REND(struct s_assenv *ae) { + struct s_expr_dico *rvar; + if (ae->ir>0) { + if (ae->repeat[ae->ir-1].cpt==-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encounter whereas referent REPEAT was waiting for UNTIL\n"); + } else { + ae->repeat[ae->ir-1].cpt--; + ae->repeat[ae->ir-1].repeat_counter++; + if ((rvar=SearchDico(ae,ae->repeat[ae->ir-1].repeatvar,ae->repeat[ae->ir-1].repeatcrc))!=NULL) { + rvar->v=ae->repeat[ae->ir-1].repeat_counter; + } + if (ae->repeat[ae->ir-1].cpt) { + ae->idx=ae->repeat[ae->ir-1].start; + /* refresh macro check index */ + ae->imacropos=ae->repeat[ae->ir-1].maxim; + } else { + ae->ir--; + /* refresh macro check index */ + if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"REND encounter whereas there is no referent REPEAT\n"); + } +} + +void __UNTIL(struct s_assenv *ae) { + if (ae->ir>0) { + if (ae->repeat[ae->ir-1].cpt>=0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] UNTIL encounter whereas referent REPEAT n was waiting for REND\n"); + } else { + if (ae->wl[ae->idx].t==0 && ae->wl[ae->idx+1].t==1) { + ae->repeat[ae->ir-1].repeat_counter++; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + if (!ComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,2)) { + if (ae->repeat[ae->ir-1].repeat_counter>65536) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Bypass infinite REPEAT loop\n"); + ae->ir--; + /* refresh macro check index */ + if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; + } else { + ae->idx=ae->repeat[ae->ir-1].start; + ae->repeat[ae->ir-1].cpt--; /* for local label */ + /* refresh macro check index */ + ae->imacropos=ae->repeat[ae->ir-1].maxim; + } + } else { + ae->ir--; + /* refresh macro check index */ + if (ae->ir) ae->imacropos=ae->repeat[ae->ir-1].maxim; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL need one expression/evaluation as parameter\n"); + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"UNTIL encounter whereas there is no referent REPEAT\n"); + } +} + +void __ASSERT(struct s_assenv *ae) { + char Dot3[4]; + int rexpr; + + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + if (strlen(ae->wl[ae->idx+1].w)>29) strcpy(Dot3,"..."); else strcpy(Dot3,""); + rexpr=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + if (!rexpr) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx+1].l,"ASSERT %.29s%s failed with ",ae->wl[ae->idx+1].w,Dot3); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); + rasm_printf(ae,"%s\n",ae->wl[ae->idx+1].w); + if (!ae->wl[ae->idx+1].t) { + ae->idx++; + rasm_printf(ae,"-> "); + __PRINT(ae); + } + __STOP(ae); + } else { + while (!ae->wl[ae->idx].t) ae->idx++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ASSERT need one expression\n"); + } +} + +void __IF(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + rexpr=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IF need one expression\n"); + } +} + +void __IF_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* do not need to compute the value in shadow execution */ + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IF need one expression\n"); + } +} + +/* test if a label or a variable where used before */ +void __IFUSED(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr,crc; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else { + if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else { + if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + rexpr=1; + } else { + rexpr=SearchUsed(ae,ae->wl[ae->idx+1].w,crc); + } + } + } + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFUSED; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFUSED need one variable or label\n"); + } +} +void __IFNUSED(struct s_assenv *ae) { + __IFUSED(ae); + ae->ifthen[ae->ii-1].v=1-ae->ifthen[ae->ii-1].v; + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_IFNUSED; +} +void __IFUSED_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFUSED; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFUSED need one variable or label\n"); + } +} +void __IFNUSED_light(struct s_assenv *ae) { + __IFUSED_light(ae); + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_IFNUSED; +} + +/* test if a label or a variable exists */ +void __IFDEF(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr,crc; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else { + if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=1; + } else { + if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + rexpr=1; + } else { + if (SearchMacro(ae,crc,ae->wl[ae->idx+1].w)>=0) { + rexpr=1; + } else { + rexpr=0; + } + } + } + } + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFDEF need one variable or label\n"); + } +} +void __IFDEF_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"GetCurrentFile(ae),ae->wl[ae->idx].l[%s:%d] FATAL - IFDEF need one variable or label\n"); + } +} +void __IFNDEF(struct s_assenv *ae) { + struct s_expr_dico *curdic=NULL; + struct s_label *curlabel=NULL; + struct s_ifthen ifthen={0}; + int rexpr,crc; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchDico(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=0; + } else { + if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL) { + rexpr=0; + } else { + if ((SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + rexpr=0; + } else { + if (SearchMacro(ae,crc,ae->wl[ae->idx+1].w)>=0) { + rexpr=0; + } else { + rexpr=1; + } + } + } + } + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNDEF need one variable or label\n"); + } +} +void __IFNDEF_light(struct s_assenv *ae) { + struct s_expr_dico *curdic=NULL; + struct s_label *curlabel=NULL; + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNDEF; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNDEF need one variable or label\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + } +} + +void __UNDEF(struct s_assenv *ae) { + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* no error when the variable to UNDEF does not exist */ + DelDico(ae,ae->wl[ae->idx+1].w,GetCRC(ae->wl[ae->idx+1].w)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"syntax is UNDEF <variable>\n"); + } + +} + + +void __SWITCH(struct s_assenv *ae) { + struct s_switchcase curswitch={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* switch store the value */ + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + curswitch.refval=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + ObjectArrayAddDynamicValueConcat((void**)&ae->switchcase,&ae->isw,&ae->msw,&curswitch,sizeof(curswitch)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SWITCH need one expression\n"); + } +} +void __CASE(struct s_assenv *ae) { + int rexpr; + + if (ae->isw) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + rexpr=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + + if (ae->switchcase[ae->isw-1].refval==rexpr) { + ae->switchcase[ae->isw-1].execute=1; + ae->switchcase[ae->isw-1].casematch=1; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE not need one parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE encounter whereas there is no referent SWITCH\n"); + } +} +void __DEFAULT(struct s_assenv *ae) { + + if (ae->isw) { + if (ae->wl[ae->idx].t==1) { + /* aucun match avant, on active, sinon on laisse tel quel */ + if (!ae->switchcase[ae->isw-1].casematch) { + ae->switchcase[ae->isw-1].execute=1; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT do not need parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT encounter whereas there is no referent SWITCH\n"); + } +} +void __BREAK(struct s_assenv *ae) { + + if (ae->isw) { + if (ae->wl[ae->idx].t==1) { + ae->switchcase[ae->isw-1].execute=0; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK do not need parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK encounter whereas there is no referent SWITCH\n"); + } +} +void __SWITCH_light(struct s_assenv *ae) { + struct s_switchcase curswitch={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + /* shadow execution */ + curswitch.refval=0; + curswitch.execute=0; + ObjectArrayAddDynamicValueConcat((void**)&ae->switchcase,&ae->isw,&ae->msw,&curswitch,sizeof(curswitch)); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SWITCH need one expression\n"); + } +} +void __CASE_light(struct s_assenv *ae) { + if (ae->isw) { + /* shadowed execution */ + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CASE encounter whereas there is no referent SWITCH\n"); + } +} +void __DEFAULT_light(struct s_assenv *ae) { + + if (ae->isw) { + /* shadowed execution */ + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"DEFAULT encounter whereas there is no referent SWITCH\n"); + } +} +void __BREAK_light(struct s_assenv *ae) { + if (ae->isw) { + /* shadowed execution */ + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"BREAK encounter whereas there is no referent SWITCH\n"); + } +} +void __ENDSWITCH(struct s_assenv *ae) { + if (ae->isw) { + if (ae->wl[ae->idx].t==1) { + ae->isw--; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSWITCH does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSWITCH encounter whereas there is no referent SWITCH\n"); + } +} + +void __IFNOT(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + int rexpr; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + rexpr=!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + ifthen.v=rexpr; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNOT; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + //IntArrayAddDynamicValueConcat(&ae->ifthen,&ae->ii,&ae->mi,rexpr); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNOT need one expression\n"); + } +} +void __IFNOT_light(struct s_assenv *ae) { + struct s_ifthen ifthen={0}; + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ifthen.v=0; + ifthen.filename=GetCurrentFile(ae); + ifthen.line=ae->wl[ae->idx].l; + ifthen.type=E_IFTHEN_TYPE_IFNOT; + ObjectArrayAddDynamicValueConcat((void **)&ae->ifthen,&ae->ii,&ae->mi,&ifthen,sizeof(ifthen)); + //IntArrayAddDynamicValueConcat(&ae->ifthen,&ae->ii,&ae->mi,rexpr); + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"IFNOT need one expression\n"); + } +} + +void __ELSE(struct s_assenv *ae) { + if (ae->ii) { + if (ae->wl[ae->idx].t==1) { + /* ELSE a executer seulement si celui d'avant est a zero */ + switch (ae->ifthen[ae->ii-1].v) { + case -1:break; + case 0:ae->ifthen[ae->ii-1].v=1;break; + case 1:ae->ifthen[ae->ii-1].v=0;break; + } + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSE; + ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; + ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSE does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSE encounter whereas there is no referent IF\n"); + } +} +void __ELSEIF(struct s_assenv *ae) { + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSEIF; + ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; + ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); + if (ae->ifthen[ae->ii-1].v) { + /* il faut signifier aux suivants qu'on va jusqu'au ENDIF */ + ae->ifthen[ae->ii-1].v=-1; + } else { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->ifthen[ae->ii-1].v=!!RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->codeadr,0,1); + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSEIF need one expression\n"); + } +} +void __ELSEIF_light(struct s_assenv *ae) { + + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + ae->ifthen[ae->ii-1].type=E_IFTHEN_TYPE_ELSEIF; + ae->ifthen[ae->ii-1].line=ae->wl[ae->idx].l; + ae->ifthen[ae->ii-1].filename=GetCurrentFile(ae); + if (ae->ifthen[ae->ii-1].v) { + /* il faut signifier aux suivants qu'on va jusqu'au ENDIF */ + ae->ifthen[ae->ii-1].v=-1; + } else { + ae->ifthen[ae->ii-1].v=0; + } + ae->idx++; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ELSEIF need one expression\n"); + } +} +void __ENDIF(struct s_assenv *ae) { + if (ae->ii) { + if (ae->wl[ae->idx].t==1) { + ae->ii--; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDIF does not need any parameter\n"); + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDIF encounter whereas there is no referent IF\n"); + } +} + +void __internal_PROTECT(struct s_assenv *ae, int memstart, int memend) { + struct s_orgzone orgzone={0}; + + /* add a fake ORG zone */ + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + /* then switch it with the current ORG */ + orgzone=ae->orgzone[ae->io-2]; + ae->orgzone[ae->io-2].memstart=memstart; + ae->orgzone[ae->io-2].memend=memend; + ae->orgzone[ae->io-2].ibank=ae->activebank; + ae->orgzone[ae->io-2].protect=1; + ae->orgzone[ae->io-1]=orgzone; +} + +void __PROTECT(struct s_assenv *ae) { + int memstart,memend; + + if (!ae->wl[ae->idx].t && !ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t==1) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + memstart=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,0,0,0); + memend=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,0,0,0); + __internal_PROTECT(ae,memstart,memend); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"PROTECT need two parameters: startadr,endadr\n"); + } +} + +void ___org_close(struct s_assenv *ae) { + if (ae->lz>=0) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Cannot ORG inside a LZ section\n"); + return; + } + __internal_UpdateLZBlockIfAny(ae); + /* close current ORG */ + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } +} + +void ___org_new(struct s_assenv *ae, int nocode) { + struct s_orgzone orgzone={0}; + int i; + + /* check current ORG request */ + for (i=0;i<ae->io;i++) { + /* aucun contrôle sur les ORG non écrits ou en NOCODE */ + if (ae->orgzone[i].memstart!=ae->orgzone[i].memend && !ae->orgzone[i].nocode) { + if (ae->orgzone[i].ibank==ae->activebank) { + if (ae->outputadr<ae->orgzone[i].memend && ae->outputadr>=ae->orgzone[i].memstart) { + if (ae->orgzone[i].protect) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ORG located a PROTECTED section [#%04X-#%04X-B%d] file [%s] line %d\n",ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank<32?ae->orgzone[i].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ORG (output at #%04X) located in a previous ORG section [#%04X-#%04X-B%d] file [%s] line %d\n",ae->outputadr,ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank<32?ae->orgzone[i].ibank:0,ae->filename[ae->orgzone[i].ifile],ae->orgzone[i].iline); + } + } + } + } + } + + OverWriteCheck(ae); + /* if there was a crunch block before, now closed */ + if (ae->lz>=0) { + ae->lz=-1; + } + orgzone.memstart=ae->outputadr; + orgzone.ibank=ae->activebank; + orgzone.ifile=ae->wl[ae->idx].ifile; + orgzone.iline=ae->wl[ae->idx].l; + orgzone.nocode=ae->nocode=nocode; + + if (nocode) { + ___output=___internal_output_nocode; + } else { + ___output=___internal_output; + } + + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); +} + +void __ORG(struct s_assenv *ae) { + ___org_close(ae); + + if (ae->wl[ae->idx+1].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,0); + ae->codeadr=RoundComputeExpression(ae,ae->wl[ae->idx+1].w,ae->outputadr,0,0); + if (!ae->wl[ae->idx+1].t && ae->wl[ae->idx+2].t!=2) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,0); + ae->outputadr=RoundComputeExpression(ae,ae->wl[ae->idx+2].w,ae->outputadr,0,0); + ae->idx+=2; + } else { + ae->outputadr=ae->codeadr; + ae->idx++; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] ORG code location[,output location]\n"); + return; + } + + ___org_new(ae,ae->nocode); +} +void __NOCODE(struct s_assenv *ae) { + if (ae->wl[ae->idx].t==1) { + ___org_close(ae); + ae->codeadrbackup=ae->codeadr; + ae->outputadrbackup=ae->outputadr; + ___org_new(ae,1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"NOCODE directive does not need parameter\n"); + } +} +void __CODE(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t) { + if (strcmp(ae->wl[ae->idx+1].w,"SKIP")==0) { + ___org_close(ae); + ae->codeadr=ae->codeadrbackup; + ae->outputadr=ae->outputadrbackup; + ___org_new(ae,1); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"unknown parameter for CODE directive\n"); + } + ae->idx++; + } else if (ae->wl[ae->idx].t==1) { + ___org_close(ae); + ___org_new(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"CODE directive does not need parameter\n"); + } +} +void __STRUCT(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__STRUCT" + struct s_rasmstructfield rasmstructfield={0}; + struct s_rasmstruct rasmstruct={0}; + struct s_rasmstruct rasmstructalias={0}; + struct s_label curlabel={0}; + int crc,i,j,irs; + /* filler */ + int localsize,cursize; + double zeval; + + if (!ae->wl[ae->idx].t) { + if (ae->wl[ae->idx+1].t) { + /************************************************** + s t r u c t u r e d e c l a r a t i o n + **************************************************/ + if (!ae->getstruct) { + /* cannot be an existing label or EQU (but variable ok) */ + crc=GetCRC(ae->wl[ae->idx+1].w); + if ((SearchLabel(ae,ae->wl[ae->idx+1].w,crc))!=NULL || (SearchAlias(ae,crc,ae->wl[ae->idx+1].w))!=-1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT name must be different from existing labels ou aliases\n"); + } else { + ae->backup_filename=GetCurrentFile(ae); + ae->backup_line=ae->wl[ae->idx].l; + ae->backup_outputadr=ae->outputadr; + ae->backup_codeadr=ae->codeadr; + ae->getstruct=1; + /* STRUCT = NOCODE + ORG 0 */ + ___org_close(ae); + ae->codeadr=0; + ___org_new(ae,1); + /* create struct */ + rasmstruct.name=TxtStrDup(ae->wl[ae->idx+1].w); + rasmstruct.crc=GetCRC(rasmstruct.name); + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct,&ae->irasmstruct,&ae->mrasmstruct,&rasmstruct,sizeof(rasmstruct)); + ae->idx++; + + /* wrapper for data capture */ + instruction[ICRC_DEFB].makemnemo=_DEFB_struct;instruction[ICRC_DB].makemnemo=_DEFB_struct; + instruction[ICRC_DEFW].makemnemo=_DEFW_struct;instruction[ICRC_DW].makemnemo=_DEFW_struct; + instruction[ICRC_DEFI].makemnemo=_DEFI_struct; + instruction[ICRC_DEFR].makemnemo=_DEFR_struct;instruction[ICRC_DR].makemnemo=_DEFR_struct; + instruction[ICRC_DEFS].makemnemo=_DEFS_struct;instruction[ICRC_DS].makemnemo=_DEFS_struct; + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT cannot be declared inside previous opened STRUCT [%s] Line %d\n",ae->backup_filename,ae->backup_line); + } + } else { + /************************************************** + s t r u c t u r e i n s e r t i o n + **************************************************/ + int nbelem=1; +#if TRACE_STRUCT +printf("structure insertion\n"); +#endif + /* insert struct param1 in memory with name param2 */ + crc=GetCRC(ae->wl[ae->idx+1].w); + /* look for existing struct */ + for (irs=0;irs<ae->irasmstruct;irs++) { + if (ae->rasmstruct[irs].crc==crc && strcmp(ae->rasmstruct[irs].name,ae->wl[ae->idx+1].w)==0) break; + } + if (irs==ae->irasmstruct) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Unknown STRUCT %s\n",ae->wl[ae->idx+1].w); + } else { + /* create alias for sizeof */ + if (!ae->getstruct) { + if (ae->wl[ae->idx+2].w[0]=='@') { + rasmstructalias.name=MakeLocalLabel(ae,ae->wl[ae->idx+2].w,NULL); + } else { + rasmstructalias.name=TxtStrDup(ae->wl[ae->idx+2].w); + } + } else { +#if TRACE_STRUCT +printf("struct [%s] inside struct\n",ae->wl[ae->idx+2].w); +#endif + /* struct inside struct */ + rasmstructalias.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+2+strlen(ae->wl[ae->idx+2].w)); + sprintf(rasmstructalias.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->wl[ae->idx+2].w); + } + rasmstructalias.crc=GetCRC(rasmstructalias.name); + rasmstructalias.size=ae->rasmstruct[irs].size; + rasmstructalias.ptr=ae->codeadr; +#if TRACE_STRUCT +printf("structalias [%s] ptr=%d size=%d\n",rasmstructalias.name,rasmstructalias.ptr,rasmstructalias.size); +#endif + /* extra parameter to declare an array? */ + if (!ae->wl[ae->idx+2].t && !StringIsQuote(ae->wl[ae->idx+3].w)) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,0); + nbelem=RoundComputeExpression(ae,ae->wl[ae->idx+3].w,ae->outputadr,0,0); + if (nbelem<1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Struct array need a positive number of elements!\n"); + nbelem=1; + } + ae->idx++; + } + rasmstructalias.nbelem=nbelem; +#if TRACE_STRUCT +printf("EVOL 119 - tableau! %d elem(s)\n",nbelem); +#endif + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstructalias,&ae->irasmstructalias,&ae->mrasmstructalias,&rasmstructalias,sizeof(rasmstructalias)); + + /* create label for global struct ptr */ + curlabel.iw=-1; + curlabel.ptr=ae->codeadr; + if (!ae->getstruct) { + if (ae->wl[ae->idx+2].w[0]=='@') curlabel.name=MakeLocalLabel(ae,ae->wl[ae->idx+2].w,NULL); else curlabel.name=TxtStrDup(ae->wl[ae->idx+2].w); + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + } else { + /* or check for non-local name in struct declaration */ + if (ae->wl[ae->idx+2].w[0]=='@') { + MakeError(ae,GetCurrentFile(ae),GetExpLine(ae,0),"Meaningless use of local label in a STRUCT definition\n"); + } else { + curlabel.name=TxtStrDup(rasmstructalias.name); + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + } + } + + /* first field is in fact the very beginning of the structure */ + if (ae->getstruct) { + rasmstructfield.name=TxtStrDup(ae->wl[ae->idx+2].w); + rasmstructfield.offset=ae->codeadr; + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, + &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, + &rasmstructfield,sizeof(rasmstructfield)); + } + + /* create subfields */ +#if TRACE_STRUCT +printf("create subfields\n"); +#endif + curlabel.iw=-1; + curlabel.ptr=ae->codeadr; + for (i=0;i<ae->rasmstruct[irs].irasmstructfield;i++) { + curlabel.ptr=ae->codeadr+ae->rasmstruct[irs].rasmstructfield[i].offset; + if (!ae->getstruct) { + curlabel.name=MemMalloc(strlen(ae->wl[ae->idx+2].w)+strlen(ae->rasmstruct[irs].rasmstructfield[i].name)+2); + sprintf(curlabel.name,"%s.%s",ae->wl[ae->idx+2].w,ae->rasmstruct[irs].rasmstructfield[i].name); + if (ae->wl[ae->idx+2].w[0]=='@') { + char *newlabel; + newlabel=MakeLocalLabel(ae,curlabel.name,NULL); + MemFree(curlabel.name); + curlabel.name=newlabel; + } + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + /* are we using a struct in a struct definition? */ + } else { + /* copy structname+label+offset in the structure */ + rasmstructfield.name=MemMalloc(strlen(ae->wl[ae->idx+2].w)+strlen(ae->rasmstruct[irs].rasmstructfield[i].name)+2); + sprintf(rasmstructfield.name,"%s.%s",ae->wl[ae->idx+2].w,ae->rasmstruct[irs].rasmstructfield[i].name); + rasmstructfield.offset=curlabel.ptr; + ObjectArrayAddDynamicValueConcat((void **)&ae->rasmstruct[ae->irasmstruct-1].rasmstructfield, + &ae->rasmstruct[ae->irasmstruct-1].irasmstructfield,&ae->rasmstruct[ae->irasmstruct-1].mrasmstructfield, + &rasmstructfield,sizeof(rasmstructfield)); + + /* need to push also generic label */ + curlabel.name=MemMalloc(strlen(ae->rasmstruct[ae->irasmstruct-1].name)+strlen(rasmstructfield.name)+2); /* overwrite PTR */ + sprintf(curlabel.name,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,rasmstructfield.name); + curlabel.crc=GetCRC(curlabel.name); + PushLabelLight(ae,&curlabel); + } + } + + /* is there any filler in the declaration? */ + localsize=0; + + /* déterminer si on est en remplissage par défaut ou remplissage surchargé */ + + + + + +#if TRACE_STRUCT +printf("struct new behaviour (scan for %d fields)\n",ae->rasmstruct[irs].irasmstructfield); +#endif +#if 0 + for (i=0;i<ae->rasmstruct[irs].irasmstructfield;i++) { + + if (!ae->wl[ae->idx+2+i].t || i+1>=ae->rasmstruct[irs].irasmstructfield) { + /* si le champ est sur le même offset que le précédent, on le saute */ + if (i && ae->rasmstruct[irs].rasmstructfield[i].offset>ae->rasmstruct[irs].rasmstructfield[i-1].offset) continue; + +#if TRACE_STRUCT +printf("get field? (%d)\n",irs); +#endif + if (!StringIsQuote(ae->wl[ae->idx+i].w)) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+i].w,1); + zeval=RoundComputeExpressionCore(ae,ae->wl[ae->idx+i].w,ae->codeadr,0); + } else { + // push string + } + + localsize+=ae->rasmstruct[irs].rasmstructfield[i].size; + + /* pour du single shot ? + pushbyte(s) at ae->codeadr+ae->rasmstruct[irs].rasmstructfield[i].offset + */ + + //ae->rasmstruct[irs].size; + + } else { +#if TRACE_STRUCT +printf("*break*\n"); +#endif + break; + } + } +#endif + + /* (LEGACY) filler, on balance des zéros */ +#if TRACE_STRUCT +printf("struct (almost) legacy filler from %d to %d-1\n",localsize,ae->rasmstruct[irs].size); +#endif + while (nbelem) { + for (i=cursize=0;i<ae->rasmstruct[irs].irasmstructfield && cursize<localsize;i++) { + cursize+=ae->rasmstruct[irs].rasmstructfield[i].size; + } + for (;i<ae->rasmstruct[irs].irasmstructfield;i++) { + for (j=0;j<ae->rasmstruct[irs].rasmstructfield[i].idata;j++) { + ___output(ae,ae->rasmstruct[irs].rasmstructfield[i].data[j]); + } + } + nbelem--; + } + +#if 0 + for (i=localsize;i<ae->rasmstruct[irs].size;i++) ___output(ae,0); +#endif + ae->idx+=2; // probablement à revoir dans le cas d'une init!!! + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"STRUCT directive needs one or two parameters\n"); + } +} +void __ENDSTRUCT(struct s_assenv *ae) { + #undef FUNC + #define FUNC "__ENDSTRUCT" + struct s_label curlabel={0}; + int i,newlen; +#if TRACE_STRUCT + printf("endstruct\n"); +#endif + + if (!ae->wl[ae->idx].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSTRUCT directive does not need parameter\n"); + } else { + if (ae->getstruct) { + ae->rasmstruct[ae->irasmstruct-1].size=ae->codeadr; + ae->getstruct=0; + + /* SIZEOF like Vasm with struct name */ + curlabel.name=TxtStrDup(ae->rasmstruct[ae->irasmstruct-1].name); + curlabel.crc=ae->rasmstruct[ae->irasmstruct-1].crc; + curlabel.iw=-1; + curlabel.ptr=ae->rasmstruct[ae->irasmstruct-1].size; + PushLabelLight(ae,&curlabel); + + /* compute size for each field */ + newlen=strlen(ae->rasmstruct[ae->irasmstruct-1].name)+2; + for (i=0;i<ae->rasmstruct[ae->irasmstruct-1].irasmstructfield-1;i++) { + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].size=ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i+1].offset-ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].offset; + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname=MemMalloc(newlen+strlen(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name)); + sprintf(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name); + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].crc=GetCRC(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname); + } + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].size=ae->rasmstruct[ae->irasmstruct-1].size-ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].offset; + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname=MemMalloc(newlen+strlen(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name)); + sprintf(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname,"%s.%s",ae->rasmstruct[ae->irasmstruct-1].name,ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].name); + ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].crc=GetCRC(ae->rasmstruct[ae->irasmstruct-1].rasmstructfield[i].fullname); + + /* unwrap data capture */ + if (ae->as80==1) {/* not for UZ80 */ + instruction[ICRC_DEFB].makemnemo=_DEFB_as80;instruction[ICRC_DB].makemnemo=_DEFB_as80; + instruction[ICRC_DEFW].makemnemo=_DEFW_as80;instruction[ICRC_DW].makemnemo=_DEFW_as80; + instruction[ICRC_DEFI].makemnemo=_DEFI_as80; + } else { + instruction[ICRC_DEFB].makemnemo=_DEFB;instruction[ICRC_DB].makemnemo=_DEFB; + instruction[ICRC_DEFW].makemnemo=_DEFW;instruction[ICRC_DW].makemnemo=_DEFW; + instruction[ICRC_DEFI].makemnemo=_DEFI; + } + instruction[ICRC_DEFR].makemnemo=_DEFR;instruction[ICRC_DR].makemnemo=_DEFR; + instruction[ICRC_DEFS].makemnemo=_DEFS;instruction[ICRC_DS].makemnemo=_DEFS; + + /* like there was no byte */ + ae->outputadr=ae->backup_outputadr; + ae->codeadr=ae->backup_codeadr; + + ___org_close(ae); + ___org_new(ae,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"ENDSTRUCT encountered outside STRUCT declaration\n"); + } + } +} + +void __MEMSPACE(struct s_assenv *ae) { + if (ae->wl[ae->idx].t) { + ___new_memory_space(ae); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MEMSPACE directive does not need parameter\n"); + } +} + +int (*_internal_getsample)(unsigned char *data, int *idx); +#undef FUNC +#define FUNC "_internal_AudioGetSampleValue" + +int __internal_getsample8(unsigned char *data, int *idx) { + unsigned char v; + v=data[*idx]-128;*idx=*idx+1;return v; +} +int __internal_getsample16little(unsigned char *data, int *idx) { + int cursample; + cursample=data[*idx+1]-0x80;*idx=*idx+2; + return cursample; +} +int __internal_getsample24little(unsigned char *data, int *idx) { + int cursample; + cursample=data[*idx+2-0x80];*idx=*idx+3; + return cursample; +} +/* big-endian */ +int __internal_getsample16big(unsigned char *data, int *idx) { + int cursample; + cursample=data[*idx]-0x80;*idx=*idx+2; + return cursample; +} +int __internal_getsample24big(unsigned char *data, int *idx) { + int cursample; + cursample=data[*idx]-0x80;*idx=*idx+3; + return cursample; +} +/* float & endian shit */ +int _isLittleEndian() /* from lz4.h */ +{ + const union { U32 u; BYTE c[4]; } one = { 1 }; + return one.c[0]; +} + +unsigned char * __internal_floatinversion(unsigned char *data) { + static unsigned char bswap[4]; + bswap[0]=data[3]; + bswap[1]=data[2]; + bswap[2]=data[1]; + bswap[3]=data[0]; + return bswap; +} + +int __internal_getsample32bigbig(unsigned char *data, int *idx) { + float fsample; + int cursample; + fsample=*((float*)(data+*idx)); + *idx=*idx+4; + cursample=(floor)((fsample+1.0)*127.5+0.5); + return cursample; +} +int __internal_getsample32biglittle(unsigned char *data, int *idx) { + float fsample; + int cursample; + fsample=*((float*)(__internal_floatinversion(data+*idx))); + *idx=*idx+4; + cursample=(floor)((fsample+1.0)*127.5+0.5); + return cursample; +} + +#define __internal_getsample32littlelittle __internal_getsample32bigbig +#define __internal_getsample32littlebig __internal_getsample32biglittle + + +void _AudioLoadSample(struct s_assenv *ae, unsigned char *data, int filesize, enum e_audio_sample_type sample_type, float normalize) +{ + #undef FUNC + #define FUNC "AudioLoadSample" + + struct s_wav_header *wav_header; + int i,j,n,idx,controlsize; + int nbchannel,bitspersample,nbsample; + int bigendian=0,cursample; + double accumulator; + unsigned char samplevalue=0, sampleprevious=0; + int samplerepeat=0,ipause; + + unsigned char *subchunk; + int subchunksize; + + if (filesize<sizeof(struct s_wav_header)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - this file is too small to be a valid WAV!\n"); + return; + } + + wav_header=(struct s_wav_header *)data; + +#if TRACE_HEXBIN +printf("AudioLoadSample filesize=%d st=%d normalize=%.2lf\n",filesize,sample_type,normalize); +#endif + if (strncmp(wav_header->ChunkID,"RIFF",4)) { + if (strncmp(wav_header->ChunkID,"RIFX",4)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported audio sample type (chunkid must be 'RIFF' or 'RIFX')\n"); + return; + } else { + bigendian=1; + } + } + if (strncmp(wav_header->Format,"WAVE",4)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"[%s:%d] WAV import - unsupported audio sample type (format must be 'WAVE')\n"); + return; + } + controlsize=wav_header->SubChunk1Size[0]+wav_header->SubChunk1Size[1]*256+wav_header->SubChunk1Size[2]*65536+wav_header->SubChunk1Size[3]*256*65536; + if (controlsize!=16) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - invalid wav chunk size (subchunk1 control)\n"); + return; + } + if (strncmp(wav_header->SubChunk1ID,"fmt",3)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported audio sample type (subchunk1id must be 'fmt')\n"); + return; + } + +#if TRACE_HEXBIN +printf("AudioLoadSample getsubchunk\n"); +#endif + subchunk=(unsigned char *)&wav_header->SubChunk2ID; + while (strncmp(subchunk,"data",4)) { + subchunksize=8+subchunk[4]+subchunk[5]*256+subchunk[6]*65536+subchunk[7]*256*65536; + if (subchunksize>=filesize) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - data subchunk not found\n"); + return; + } + subchunk+=subchunksize; + } + subchunksize=subchunk[4]+subchunk[5]*256+subchunk[6]*65536+subchunk[7]*256*65536; + controlsize=subchunksize; + + nbchannel=wav_header->NumChannels[0]+wav_header->NumChannels[1]*256; + if (nbchannel<1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - invalid number of audio channel\n"); + return; + } + bitspersample=wav_header->BitsPerSample[0]+wav_header->BitsPerSample[1]*256; +#if TRACE_HEXBIN +printf("AudioLoadSample bitpersample=%d\n",bitspersample); +#endif + switch (bitspersample) { + case 8:_internal_getsample=__internal_getsample8;break; + case 16:if (!bigendian) _internal_getsample=__internal_getsample16little; else _internal_getsample=__internal_getsample16big;break; + case 24:if (!bigendian) _internal_getsample=__internal_getsample24little; else _internal_getsample=__internal_getsample24big;break; + case 32:if (!bigendian) { + if (_isLittleEndian()) { + _internal_getsample=__internal_getsample32littlelittle; + } else { + _internal_getsample=__internal_getsample32littlebig; + } + } else { + if (_isLittleEndian()) { + _internal_getsample=__internal_getsample32biglittle; + } else { + _internal_getsample=__internal_getsample32bigbig; + } + } + break; + default: + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - unsupported bits per sample (%d)\n",bitspersample); + return; + } + + nbsample=controlsize/nbchannel/(bitspersample/8); + if (controlsize+sizeof(struct s_wav_header)>filesize) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"WAV import - cannot read %d byte%s of audio whereas the file is %d bytes big!\n",controlsize,controlsize>1?"s":"",filesize); + return; + } + +#if TRACE_HEXBIN +printf("nbsample=%d (sze=%d,chn=%d,bps=%d) st=%c\n",nbsample,controlsize,nbchannel,bitspersample,sample_type); +#endif + + idx=subchunk-data; + switch (sample_type) { + default: + case AUDIOSAMPLE_SMP: + for (i=0;i<nbsample;i++) { + /* downmixing */ + accumulator=0.0; + for (n=0;n<nbchannel;n++) { + accumulator+=_internal_getsample(data,&idx); + } + /* normalize */ + cursample=MinMaxInt(floor(((accumulator/nbchannel)*normalize)+0.5)+128,0,255); + + /* PSG levels */ + samplevalue=ae->psgfine[cursample]; + + /* output */ + ___output(ae,samplevalue); + } + break; + case AUDIOSAMPLE_SM2: + /* +1 pour éviter le segfault */ + for (i=0;i<nbsample+1;i+=2) { + for (j=0;j<2;j++) { + /* downmixing */ + accumulator=0.0; + for (n=0;n<nbchannel;n++) { + accumulator+=_internal_getsample(data,&idx); + } + /* normalize */ + cursample=MinMaxInt(floor(((accumulator/nbchannel)*normalize)+0.5)+128,0,255); + /* PSG levels & packing */ + samplevalue=(samplevalue<<4)+(ae->psgfine[cursample]); + } + + /* output */ + ___output(ae,samplevalue); + } + break; + case AUDIOSAMPLE_SM4: + /*** + SM4 format has two bits + bits -> PSG value + 00 -> 0 + 01 -> 13 + 10 -> 14 + 11 -> 15 + ***/ + /* +3 pour éviter le segfault */ + for (i=0;i<nbsample+3;i+=4) { + for (j=0;j<4;j++) { + /* downmixing */ + accumulator=0.0; + for (n=0;n<nbchannel;n++) { + accumulator+=_internal_getsample(data,&idx); + } + /* normalize */ + cursample=MinMaxInt(floor(((accumulator/nbchannel)*normalize)+0.5)+128,0,255); + /* PSG levels & packing */ + samplevalue=(samplevalue<<2)+(ae->psgtab[cursample]>>2); + } + /* output */ + ___output(ae,samplevalue); + } + break; + case AUDIOSAMPLE_DMA: + sampleprevious=255; + for (i=0;i<nbsample;i++) { + /* downmixing */ + accumulator=0.0; + for (n=0;n<nbchannel;n++) { + accumulator+=_internal_getsample(data,&idx); + } + /* normalize */ + cursample=MinMaxInt(floor(((accumulator/nbchannel)*normalize)+0.5)+128,0,255); + + /* PSG levels */ + samplevalue=ae->psgtab[cursample]; + + if (samplevalue==sampleprevious) { + samplerepeat++; + } else { + if (!samplerepeat) { + /* DMA output */ + ___output(ae,sampleprevious); + ___output(ae,0x0A); /* volume canal C */ + } else { + /* DMA pause */ + ___output(ae,sampleprevious); + ___output(ae,0x0A); /* volume canal C */ + while (samplerepeat) { + ipause=samplerepeat<4096?samplerepeat:4095; + ___output(ae,ipause&0xFF); + ___output(ae,0x10 | ((ipause>>8) &0xF)); /* pause */ + + samplerepeat-=4096; + if (samplerepeat<0) samplerepeat=0; + } + } + sampleprevious=samplevalue; + } + } + if (samplerepeat) { + /* DMA pause */ + ___output(ae,sampleprevious); + ___output(ae,0x0A); /* volume canal C */ + while (samplerepeat) { + ipause=samplerepeat<4096?samplerepeat:4095; + ___output(ae,ipause&0xFF); + ___output(ae,0x10 | ((ipause>>8) &0xF)); /* pause */ + + samplerepeat-=4096; + if (samplerepeat<0) samplerepeat=0; + } + } + ___output(ae,0); + ___output(ae,0x0A); /* volume canal C */ + ___output(ae,0x20); + ___output(ae,0x40); /* stop or reloop? */ + break; + } +} + +/* + meta fonction qui gère le INCBIN standard plus les variantes SMP et DMA +*/ +void __HEXBIN(struct s_assenv *ae) { + int hbinidx,overwritecheck=1,crc; + struct s_expr_dico *rvar; + unsigned int idx; + int size=0,offset=0; + float amplification=1.0; + int deload=0; + int vtiles=0,remap=0,revert=0; + int itiles=0,tilex; + + if (!ae->wl[ae->idx].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+1].w,1); + hbinidx=RoundComputeExpressionCore(ae,ae->wl[ae->idx+1].w,ae->codeadr,0); + if (hbinidx>ae->ih) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"internal error with binary file import (index out of bounds)\n"); + return; + } +#if TRACE_HEXBIN +printf("Hexbin idx=[%s] filename=[%s]\n",ae->wl[ae->idx+1].w,ae->hexbin[hbinidx].filename); +#endif + + if (!ae->wl[ae->idx+1].t) { + if (strcmp("DSK",ae->wl[ae->idx+2].w)==0) { + /* import binary from DSK */ + } else if (strchr("SD",ae->wl[ae->idx+2].w[0]) && ae->wl[ae->idx+2].w[1]=='M' && + strchr("P24A",ae->wl[ae->idx+2].w[2]) && !ae->wl[ae->idx+2].w[3]) { + /* SMP,SM2,SM4,DMA */ + +#if TRACE_HEXBIN +printf("Hexbin -> %s\n",ae->wl[ae->idx+2].w); +#endif + if (!ae->wl[ae->idx+2].t) { + amplification=ComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); +#if TRACE_HEXBIN +printf("sample amplification=%.2lf\n",amplification); +#endif + } + + switch (ae->wl[ae->idx+2].w[2]) { + case 'P':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SMP,amplification);break; + case '2':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SM2,amplification);break; + case '4':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_SM4,amplification);break; + case 'A':_AudioLoadSample(ae,ae->hexbin[hbinidx].data,ae->hexbin[hbinidx].datalen, AUDIOSAMPLE_DMA,amplification);break; + default:printf("warning remover\n");break; + } + ae->idx+=2; + return; + } else { + /* legacy binary file */ +#if TRACE_HEXBIN +printf("Hexbin legacy datalen=%d\n",ae->hexbin[hbinidx].datalen); +#endif + if (strcmp("REVERT",ae->wl[ae->idx+2].w)==0) { + /* revert data */ + if (!ae->wl[ae->idx+2].t) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REVERT does not need extra parameters\n"); + } +#if TRACE_HEXBIN +printf(" -> REVERT loading\n"); +#endif + revert=1; + offset=size=0; // full file + ae->idx++; + + } else if (strcmp("REMAP",ae->wl[ae->idx+2].w)==0) { + /* reorder tiles data */ + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + remap=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REMAP need a number of columns for reordering\n"); + } +#if TRACE_HEXBIN +printf(" -> REMAP loading\n"); +#endif + offset=size=0; // full file + ae->idx+=2; + + } else if (strcmp("ITILES",ae->wl[ae->idx+2].w)==0) { + /*** entrelace les tiles, besoin de hauteur et largeur de la tile ***/ + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + tilex=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); + itiles=1; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"usage is INCBIN'file',ITILES,width\n"); + } +#if TRACE_HEXBIN +printf(" -> ITILES loading\n"); +#endif + offset=size=0; // full file + ae->idx+=2; + } else if (strcmp("VTILES",ae->wl[ae->idx+2].w)==0) { + /* import and reorder tiles */ + if (!ae->wl[ae->idx+2].t) { + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); + vtiles=RoundComputeExpressionCore(ae,ae->wl[ae->idx+3].w,ae->codeadr,0); + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN VTILES need a number of lines for reordering\n"); + } +#if TRACE_HEXBIN +printf(" -> VTILES loading\n"); +#endif + offset=size=0; // full file + ae->idx+=2; + } else { + char *expwrk; + + expwrk=TxtStrDup(ae->wl[ae->idx+2].w); + ExpressionFastTranslate(ae,&expwrk,1); + offset=RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); + MemFree(expwrk); +#if TRACE_HEXBIN + printf("offset=%d\n",offset); +#endif + if (!ae->wl[ae->idx+2].t) { + if (ae->wl[ae->idx+3].w[0]) { + expwrk=TxtStrDup(ae->wl[ae->idx+3].w); + ExpressionFastTranslate(ae,&expwrk,1); + size=RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); + MemFree(expwrk); + } else { + size=0; + } +#if TRACE_HEXBIN + printf("size=%d\n",size); +#endif + if (size<-65535 || size>65536) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN invalid size\n"); + } + if (!ae->wl[ae->idx+3].t) { + if (ae->wl[ae->idx+4].w[0]) { + expwrk=TxtStrDup(ae->wl[ae->idx+4].w); + ExpressionFastTranslate(ae,&expwrk,1); + offset+=65536*RoundComputeExpressionCore(ae,expwrk,ae->codeadr,0); + MemFree(expwrk); + } + if (!ae->wl[ae->idx+4].t) { + if (strcmp(ae->wl[ae->idx+5].w,"OFF")==0) { + overwritecheck=0; + } else if (strcmp(ae->wl[ae->idx+5].w,"ON")==0) { + overwritecheck=1; +#if TRACE_HEXBIN + printf("mode OVERWRITE\n"); +#endif + } else if (ae->wl[ae->idx+5].w[0]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN invalid overwrite value. Must be 'OFF' or 'ON'\n"); + } + if (!ae->wl[ae->idx+5].t) { + /* copy raw len to a (new) variable */ + crc=GetCRC(ae->wl[ae->idx+6].w); + if ((rvar=SearchDico(ae,ae->wl[ae->idx+6].w,crc))!=NULL) { + rvar->v=ae->hexbin[hbinidx].rawlen; + } else { + /* mais ne peut être un label ou un alias */ + ExpressionSetDicoVar(ae,ae->wl[ae->idx+6].w,ae->hexbin[hbinidx].rawlen); + } + ae->idx+=6; + } else { + ae->idx+=5; + } + } else { + ae->idx+=4; + } + } else { + ae->idx+=3; + } + } else { + ae->idx+=2; + } + } + } + } else { + ae->idx++; + } + + /* preprocessor cannot manage variables so here is the delayed load */ + if (ae->hexbin[hbinidx].datalen<0) { + struct s_hexbin *curhexbin; + char *newfilename; + int lm,touched; + unsigned char *newdata=NULL; + +#if TRACE_HEXBIN +printf("Hexbin -> as only the assembler know how to deal with var,\n"); +printf("we look for tags in the name of a file which were not found\n"); +#endif + curhexbin=&ae->hexbin[hbinidx]; + + newfilename=TxtStrDup(curhexbin->filename); + + /* need to upper case tags */ + for (lm=touched=0;newfilename[lm];lm++) { + if (newfilename[lm]=='{') touched++; else if (newfilename[lm]=='}') touched--; else if (touched) newfilename[lm]=toupper(newfilename[lm]); + } + /* on essaie d'interpréter le nom du fichier en dynamique */ + newfilename=TranslateTag(ae,newfilename,&touched,1,E_TAGOPTION_REMOVESPACE); + /* load */ + if (FileExists(newfilename)) { +#if TRACE_HEXBIN +printf("Hexbin -> surprise! we found the file!\n"); +#endif + curhexbin->rawlen=curhexbin->datalen=FileGetSize(newfilename); + curhexbin->data=MemMalloc(curhexbin->datalen*1.3+10); + if (FileReadBinary(newfilename,(char*)curhexbin->data,curhexbin->datalen)!=curhexbin->datalen) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"read error on file [%s]\n",newfilename); + return; + } + FileReadBinaryClose(newfilename); + + switch (curhexbin->crunch) { + #ifndef NO_3RD_PARTIES + case 4: + newdata=LZ4_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); + MemFree(curhexbin->data); + curhexbin->data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ4 into %d byte(s)\n",curhexbin->datalen); + #endif + break; + case 7: + { + size_t slzlen; + newdata=ZX7_compress(optimize(curhexbin->data, curhexbin->datalen), curhexbin->data, curhexbin->datalen, &slzlen); + curhexbin->datalen=slzlen; + MemFree(curhexbin->data); + curhexbin->data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with ZX7 into %d byte(s)\n",curhexbin->datalen); + #endif + } + break; + case 8: + rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",curhexbin->datalen/1024.0); + newdata=Exomizer_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); + MemFree(curhexbin->data); + curhexbin->data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with Exomizer into %d byte(s)\n",curhexbin->datalen); + #endif + break; + #endif + case 48: + newdata=LZ48_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); + MemFree(curhexbin->data); + curhexbin->data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ48 into %d byte(s)\n",curhexbin->datalen); + #endif + break; + case 49: + newdata=LZ49_crunch(curhexbin->data,curhexbin->datalen,&curhexbin->datalen); + MemFree(curhexbin->data); + curhexbin->data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ49 into %d byte(s)\n",curhexbin->datalen); + #endif + break; + default:break; + } + deload=1; + } else { + /* still not found */ + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"file not found [%s]\n",newfilename); + return; + } + } + + if (ae->hexbin[hbinidx].datalen>0) { + if (hbinidx<ae->ih && hbinidx>=0) { + if (size<0) { +#if TRACE_HEXBIN +printf("taille négative %d -> conversion en %d\n",size,ae->hexbin[hbinidx].datalen+size); +#endif + size=ae->hexbin[hbinidx].datalen+size; + if (size<1) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN negative size is greater or equal to filesize\n"); + } + } + /* negative offset conversion */ + if (offset<0) { +#if TRACE_HEXBIN +printf("offset négatif %d -> conversion en %d\n",offset,ae->hexbin[hbinidx].datalen+offset); +#endif + offset=ae->hexbin[hbinidx].datalen+offset; + } + if (!size) { + if (!offset) { + size=ae->hexbin[hbinidx].datalen; + } else { + size=ae->hexbin[hbinidx].datalen-offset; + } +#if TRACE_HEXBIN +printf("taille nulle et offset=%d -> conversion en %d\n",offset,size); +#endif + } + if (size>ae->hexbin[hbinidx].datalen) { + rasm_printf(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN size is greater than filesize\n"); + } else { + if (size+offset>ae->hexbin[hbinidx].datalen) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN size+offset is greater than filesize\n"); + } else { + if (revert) { + int p; + p=size-1; + while (p>=0) { + ___output(ae,ae->hexbin[hbinidx].data[p--]); + } + } else if (itiles) { + /* tiles data reordering */ + int tx,ty,it,width; + + if (size % (tilex*8)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN ITILES cannot reorder tiles %d bytewidth with file of size %d\n",tilex,size); + } else { + it=0; + while (it<size) { + for (tx=0;tx<tilex;tx++) ___output(ae,ae->hexbin[hbinidx].data[it+tx+0*tilex]); + for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+1*tilex]); + for (tx=0;tx<tilex;tx++) ___output(ae,ae->hexbin[hbinidx].data[it+tx+3*tilex]); + for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+2*tilex]); + for (tx=0;tx<tilex;tx++) ___output(ae,ae->hexbin[hbinidx].data[it+tx+6*tilex]); + for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+7*tilex]); + for (tx=0;tx<tilex;tx++) ___output(ae,ae->hexbin[hbinidx].data[it+tx+5*tilex]); + for (tx=tilex-1;tx>=0;tx--) ___output(ae,ae->hexbin[hbinidx].data[it+tx+4*tilex]); + it+=tilex*8; + } + } + } else if (remap) { + /* tiles data reordering */ + int tx,ty,it,width; + + width=size/remap; + + if ((size % remap) || (remap*width>size)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN REMAP cannot reorder %d columns%s with file of size %d\n",remap,remap>1?"s":"",size); + } else { + for (it=0;it<remap;it++) { + for (tx=0;tx<width;tx++) { + ___output(ae,ae->hexbin[hbinidx].data[it+tx*remap]); + } + } + } + + } else if (vtiles) { + /* tiles map reordering */ + int width,tilex,tiley; + + width=size/vtiles; + + if ((size % vtiles) || (vtiles*width>size)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INCBIN VTILES cannot reorder %d line%s with file of size %d\n",vtiles,vtiles>1?"s":"",size); + } else { +#if TRACE_HEXBIN +printf("Hexbin -> re-tiling MAP! width=%d\n",width); +#endif + for (idx=tilex=tiley=0;idx<size;idx++) { + ___output(ae,ae->hexbin[hbinidx].data[tilex+tiley*width]); + tiley++; + if (tiley>=vtiles) { + tiley=0; + tilex++; + } + } + } + } else { + /* legacy HEXBIN */ + if (overwritecheck) { + for (idx=offset;idx<size+offset;idx++) { + ___output(ae,ae->hexbin[hbinidx].data[idx]); + } + } else { + ___org_close(ae); + ___org_new(ae,0); + for (idx=offset;idx<size+offset;idx++) { + ___output(ae,ae->hexbin[hbinidx].data[idx]); + } + /* hack to disable overwrite check */ + ae->orgzone[ae->io-1].nocode=2; + ___org_close(ae); + ___org_new(ae,0); + } + } + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL - HEXBIN refer to unknown structure\n"); + FreeAssenv(ae); + exit(2); + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"INTERNAL - HEXBIN need one HEX parameter\n"); + FreeAssenv(ae); + exit(2); + } + + /* generated names must be reloaded! */ + if (deload) { + ae->hexbin[hbinidx].datalen=-1; + MemFree(ae->hexbin[hbinidx].data); + } +} + +/* +save "nom",start,size -> save binary +save "nom",start,size,TAPE -> save tape file +save "nom",start,size,AMSDOS -> save binary with Amsdos header +save "nom",start,size,DSK,"dskname" -> save binary on DSK data format +save "nom",start,size,DSK,"dskname",B -> select face +save "nom",start,size,DSK,B -> current DSK, choose face +save "nom",start,size,DSK -> current DSK, current face +*/ +void __SAVE(struct s_assenv *ae) { + struct s_save cursave={0}; + unsigned int offset=0,size=0; + int ko=1; + + if (!ae->wl[ae->idx].t) { + /* nom de fichier entre quotes ou bien mot clef DSK */ + if (!StringIsQuote(ae->wl[ae->idx+1].w)) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SAVE invalid filename quote\n"); + ko=0; + } else { + if (!ae->wl[ae->idx+1].t) { + if (!ae->wl[ae->idx+2].t && ae->wl[ae->idx+3].t!=2) { + cursave.ibank=ae->activebank; + cursave.ioffset=ae->idx+2; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+2].w,1); // si on utilise des variables ça évite la grouille post traitement... + cursave.isize=ae->idx+3; + ExpressionFastTranslate(ae,&ae->wl[ae->idx+3].w,1); // idem + cursave.iw=ae->idx+1; + cursave.irun=ae->current_run_idx; + if (!ae->wl[ae->idx+3].t) { + if (strcmp(ae->wl[ae->idx+4].w,"TAPE")==0) { + cursave.tape=1; + } else if (strcmp(ae->wl[ae->idx+4].w,"AMSDOS")==0) { + cursave.amsdos=1; + } else if (strcmp(ae->wl[ae->idx+4].w,"HOBETA")==0) { + cursave.hobeta=1; + } else if (strcmp(ae->wl[ae->idx+4].w,"DSK")==0) { +#if TRACE_EDSK + printf("DSK SAVE order [bnk: %d ioff: %d isiz: %d iw=%d [%s] [%s]\n",cursave.ibank,cursave.ioffset,cursave.isize,cursave.iw,ae->wl[ae->idx+2].w,ae->wl[ae->idx+3].w); +#endif + cursave.dsk=1; + if (!ae->wl[ae->idx+4].t) { + cursave.iwdskname=ae->idx+5; + if (!ae->wl[ae->idx+5].t) { + /* face selection - 0 as default */ + switch (ae->wl[ae->idx+6].w[0]) { + case '1': + case 'B': + cursave.face=1; + break; + case '0': + case 'A': + default: + cursave.face=0; + break; + } + } + } else { + if (ae->nbsave && ae->save[ae->nbsave-1].iwdskname!=-1) { + cursave.iwdskname=ae->save[ae->nbsave-1].iwdskname; /* previous DSK */ + cursave.face=ae->save[ae->nbsave-1].face; /* previous face */ + } else { + cursave.iwdskname=-1; + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"cannot autoselect DSK as there was not a previous selection\n"); + } + } + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"SAVE 4th parameter must be empty or AMSDOS or DSK\n"); + ko=0; + } + } + ObjectArrayAddDynamicValueConcat((void**)&ae->save,&ae->nbsave,&ae->maxsave,&cursave,sizeof(cursave)); + ko=0; + } + } + } + } + if (ko) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"Use SAVE 'filename',offset,size[,AMSDOS|DSK[,A|B|'dskname'[,A|B]]]\n"); + } + while (!ae->wl[ae->idx].t) ae->idx++; +} + + +void __MODULE(struct s_assenv *ae) { + if (!ae->wl[ae->idx].t && ae->wl[ae->idx+1].t==1) { + if (StringIsQuote(ae->wl[ae->idx+1].w)) { + if (ae->modulen || ae->module) { + MemFree(ae->module); + } + ae->modulen=strlen(ae->wl[ae->idx+1].w); + ae->module=MemMalloc(ae->modulen); + /* duplicate and remove quotes */ + strcpy(ae->module,ae->wl[ae->idx+1].w+1); + ae->module[--ae->modulen]=0; + } else { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"MODULE directive need one text parameter\n"); + } + ae->idx++; + } else { + if (ae->module) MemFree(ae->module); + ae->module=NULL; + } +} + +void __TIMESTR(struct s_assenv *ae) { + +} + +struct s_asm_keyword instruction[]={ +{"LD",0,_LD}, +{"DEC",0,_DEC}, +{"INC",0,_INC}, +{"ADD",0,_ADD}, +{"SUB",0,_SUB}, +{"OR",0,_OR}, +{"AND",0,_AND}, +{"XOR",0,_XOR}, +{"POP",0,_POP}, +{"PUSH",0,_PUSH}, +{"DJNZ",0,_DJNZ}, +{"JR",0,_JR}, +{"JP",0,_JP}, +{"CALL",0,_CALL}, +{"RET",0,_RET}, +{"EX",0,_EX}, +{"ADC",0,_ADC}, +{"SBC",0,_SBC}, +{"EXA",0,_EXA}, +{"EXX",0,_EXX}, +{"CP",0,_CP}, +{"BIT",0,_BIT}, +{"RES",0,_RES}, +{"SET",0,_SET}, +{"IN",0,_IN}, +{"OUT",0,_OUT}, +{"RLC",0,_RLC}, +{"RRC",0,_RRC}, +{"RL",0,_RL}, +{"RR",0,_RR}, +{"SLA",0,_SLA}, +{"SRA",0,_SRA}, +{"SLL",0,_SLL}, +{"SL1",0,_SLL}, +{"SRL",0,_SRL}, +{"RST",0,_RST}, +{"HALT",0,_HALT}, +{"DI",0,_DI}, +{"EI",0,_EI}, +{"NOP",0,_NOP}, +{"DEFR",0,_DEFR}, +{"DEFB",0,_DEFB}, +{"DEFM",0,_DEFB}, +{"DR",0,_DEFR}, +{"DM",0,_DEFB}, +{"DB",0,_DEFB}, +{"DEFW",0,_DEFW}, +{"DW",0,_DEFW}, +{"DEFS",0,_DEFS}, +{"DS",0,_DEFS}, +{"STR",0,_STR}, +{"LDI",0,_LDI}, +{"LDIR",0,_LDIR}, +{"OUTI",0,_OUTI}, +{"INI",0,_INI}, +{"RLCA",0,_RLCA}, +{"RRCA",0,_RRCA}, +{"NEG",0,_NEG}, +{"RLA",0,_RLA}, +{"RRA",0,_RRA}, +{"RLD",0,_RLD}, +{"RRD",0,_RRD}, +{"DAA",0,_DAA}, +{"CPL",0,_CPL}, +{"SCF",0,_SCF}, +{"LDD",0,_LDD}, +{"LDDR",0,_LDDR}, +{"CCF",0,_CCF}, +{"OUTD",0,_OUTD}, +{"IND",0,_IND}, +{"RETI",0,_RETI}, +{"RETN",0,_RETN}, +{"IM",0,_IM}, +{"DEFI",0,_DEFI}, +{"CPD",0,_CPD}, +{"CPI",0,_CPI}, +{"CPDR",0,_CPDR}, +{"CPIR",0,_CPIR}, +{"OTDR",0,_OTDR}, +{"OTIR",0,_OTIR}, +{"INDR",0,_INDR}, +{"INIR",0,_INIR}, +{"REPEAT",0,__REPEAT}, +{"REND",0,__REND}, +{"ENDREPEAT",0,__REND}, +{"ENDREP",0,__REND}, +{"UNTIL",0,__UNTIL}, +{"ORG",0,__ORG}, +{"PROTECT",0,__PROTECT}, +{"WHILE",0,__WHILE}, +{"WEND",0,__WEND}, +{"HEXBIN",0,__HEXBIN}, +{"ALIGN",0,__ALIGN}, +{"ELSEIF",0,__ELSEIF}, +{"ELSE",0,__ELSE}, +{"IF",0,__IF}, +{"ENDIF",0,__ENDIF}, +{"IFNOT",0,__IFNOT}, +{"IFDEF",0,__IFDEF}, +{"IFNDEF",0,__IFNDEF}, +{"IFUSED",0,__IFUSED}, +{"IFNUSED",0,__IFNUSED}, +{"UNDEF",0,__UNDEF}, +{"CASE",0,__CASE}, +{"BREAK",0,__BREAK}, +{"DEFAULT",0,__DEFAULT}, +{"SWITCH",0,__SWITCH}, +{"ENDSWITCH",0,__ENDSWITCH}, +{"WRITE",0,__WRITE}, +{"CODE",0,__CODE}, +{"NOCODE",0,__NOCODE}, +{"MEMSPACE",0,__MEMSPACE}, +{"MACRO",0,__MACRO}, +{"TICKER",0,__TICKER}, +{"LET",0,__LET}, +{"ASSERT",0,__ASSERT}, +{"CHARSET",0,__CHARSET}, +{"RUN",0,__RUN}, +{"SAVE",0,__SAVE}, +{"BRK",0,__BRK}, +{"NOLIST",0,__NOLIST}, +{"LIST",0,__LIST}, +{"STOP",0,__STOP}, +{"PRINT",0,__PRINT}, +{"FAIL",0,__FAIL}, +{"BREAKPOINT",0,__BREAKPOINT}, +{"BANK",0,__BANK}, +{"BANKSET",0,__BANKSET}, +{"NAMEBANK",0,__NameBANK}, +{"LIMIT",0,__LIMIT}, +{"LZEXO",0,__LZEXO}, +{"LZX7",0,__LZX7}, +{"LZ4",0,__LZ4}, +{"LZ48",0,__LZ48}, +{"LZ49",0,__LZ49}, +{"LZCLOSE",0,__LZCLOSE}, +{"BUILDZX",0,__BUILDZX}, +{"BUILDCPR",0,__BUILDCPR}, +{"BUILDSNA",0,__BUILDSNA}, +{"BUILDTAPE",0,__BUILDTAPE}, +{"SETCPC",0,__SETCPC}, +{"SETCRTC",0,__SETCRTC}, +{"AMSDOS",0,__AMSDOS}, +{"OTD",0,_OUTD}, +{"OTI",0,_OUTI}, +{"SHL",0,_SLA}, +{"SHR",0,_SRL}, +{"STRUCT",0,__STRUCT}, +{"ENDSTRUCT",0,__ENDSTRUCT}, +{"ENDS",0,__ENDSTRUCT}, +{"NOEXPORT",0,__NOEXPORT}, +{"ENOEXPORT",0,__ENOEXPORT}, +{"",0,NULL} +}; + +int Assemble(struct s_assenv *ae, unsigned char **dataout, int *lenout, struct s_rasm_info **debug) +{ + #undef FUNC + #define FUNC "Assemble" + + unsigned char *AmsdosHeader; + struct s_expression curexp={0}; + struct s_wordlist *wordlist; + struct s_expr_dico curdico={0}; + struct s_label *curlabel; + int icrc,curcrc,i,j,k; + unsigned char *lzdata=NULL; + int lzlen,lzshift,input_size; + size_t slzlen; + unsigned char *input_data; + struct s_orgzone orgzone={0}; + int iorgzone,ibank,offset,endoffset; + int il,maxrom; + char *TMP_filename=NULL; + int minmem=65536,maxmem=0,lzmove; + char symbol_line[1024]; + int ifast,executed; + /* debug */ + int curii,inhibe; + int ok; + + rasm_printf(ae,KAYGREEN"Assembling\n"); +#if TRACE_ASSEMBLE +printf("assembling\n"); +#endif +#if TRACE_GENERALE +printf("*** assembling ***\n"); +#endif + + ae->retdebug=debug; + + srand((unsigned)time(0)); + + wordlist=ae->wl; + ae->wl=wordlist; + /* start outside crunched section */ + ae->lz=-1; + + /* default orgzone */ + orgzone.ibank=BANK_MAX_NUMBER; + ObjectArrayAddDynamicValueConcat((void**)&ae->orgzone,&ae->io,&ae->mo,&orgzone,sizeof(orgzone)); + ___output=___internal_output; + /* init des automates */ + InitAutomate(ae->AutomateHexa,AutomateHexaDefinition); + InitAutomate(ae->AutomateDigit,AutomateDigitDefinition); + InitAutomate(ae->AutomateValidLabel,AutomateValidLabelDefinition); + InitAutomate(ae->AutomateValidLabelFirst,AutomateValidLabelFirstDefinition); + InitAutomate(ae->AutomateExpressionValidCharExtended,AutomateExpressionValidCharExtendedDefinition); + InitAutomate(ae->AutomateExpressionValidCharFirst,AutomateExpressionValidCharFirstDefinition); + InitAutomate(ae->AutomateExpressionValidChar,AutomateExpressionValidCharDefinition); + ae->AutomateExpressionDecision['<']='<'; + ae->AutomateExpressionDecision['>']='>'; + ae->AutomateExpressionDecision['=']='='; + ae->AutomateExpressionDecision['!']='!'; + ae->AutomateExpressionDecision[0]='E'; + /* gestion d'alias */ + ae->AutomateExpressionDecision['~']='~'; + /* set operator precedence */ + if (!ae->maxam) { + for (i=0;i<256;i++) { + switch (i) { + /* priority 0 */ + case '(':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OPEN;ae->AutomateElement[i].priority=0;break; + case ')':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_CLOSE;ae->AutomateElement[i].priority=0;break; + /* priority 1 */ + case 'b':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOT;ae->AutomateElement[i].priority=1;break; + /* priority 2 */ + case '*':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MUL;ae->AutomateElement[i].priority=2;break; + case '/':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_DIV;ae->AutomateElement[i].priority=2;break; + case 'm':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MOD;ae->AutomateElement[i].priority=2;break; + /* priority 3 */ + case '+':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_ADD;ae->AutomateElement[i].priority=3;break; + case '-':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SUB;ae->AutomateElement[i].priority=3;break; + /* priority 4 */ + case '[':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHL;ae->AutomateElement[i].priority=4;break; + case ']':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHR;ae->AutomateElement[i].priority=4;break; + /* priority 5 */ + case 'l':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWER;ae->AutomateElement[i].priority=5;break; + case 'g':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATER;ae->AutomateElement[i].priority=5;break; + case 'e':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_EQUAL;ae->AutomateElement[i].priority=5;break; + case 'n':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOTEQUAL;ae->AutomateElement[i].priority=5;break; + case 'k':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWEREQ;ae->AutomateElement[i].priority=5;break; + case 'h':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATEREQ;ae->AutomateElement[i].priority=5;break; + /* priority 6 */ + case '&':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_AND;ae->AutomateElement[i].priority=6;break; + /* priority 7 */ + case '^':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_XOR;ae->AutomateElement[i].priority=7;break; + /* priority 8 */ + case '|':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OR;ae->AutomateElement[i].priority=8;break; + /* priority 9 */ + case 'a':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BAND;ae->AutomateElement[i].priority=9;break; + /* priority 10 */ + case 'o':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BOR;ae->AutomateElement[i].priority=10;break; + default:ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_END; + } + } + } else { + for (i=0;i<256;i++) { + switch (i) { + /* priority 0 */ + case '(':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OPEN;ae->AutomateElement[i].priority=0;break; + case ')':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_CLOSE;ae->AutomateElement[i].priority=0;break; + /* priority 0.5 */ + case 'b':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOT;ae->AutomateElement[i].priority=128;break; + /* priority 1 */ + case '*':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MUL;ae->AutomateElement[i].priority=464;break; + case '/':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_DIV;ae->AutomateElement[i].priority=464;break; + case 'm':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_MOD;ae->AutomateElement[i].priority=464;break; + case '+':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_ADD;ae->AutomateElement[i].priority=464;break; + case '-':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SUB;ae->AutomateElement[i].priority=464;break; + case '[':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHL;ae->AutomateElement[i].priority=464;break; + case ']':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_SHR;ae->AutomateElement[i].priority=464;break; + case '&':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_AND;ae->AutomateElement[i].priority=464;break; + case '^':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_XOR;ae->AutomateElement[i].priority=464;break; + case '|':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_OR;ae->AutomateElement[i].priority=464;break; + /* priority 2 */ + case 'l':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWER;ae->AutomateElement[i].priority=664;break; + case 'g':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATER;ae->AutomateElement[i].priority=664;break; + case 'e':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_EQUAL;ae->AutomateElement[i].priority=664;break; + case 'n':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_NOTEQUAL;ae->AutomateElement[i].priority=664;break; + case 'k':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_LOWEREQ;ae->AutomateElement[i].priority=664;break; + case 'h':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_GREATEREQ;ae->AutomateElement[i].priority=664;break; + /* priority 3 */ + case 'a':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BAND;ae->AutomateElement[i].priority=6128;break; + case 'o':ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_BOR;ae->AutomateElement[i].priority=6128;break; + default:ae->AutomateElement[i].operator=E_COMPUTE_OPERATION_END; + } + } + } + + /* psg conversion */ + for (i=j=0;i<100;i++) ae->psgtab[j++]=0; + for (i=0;i<49;i++) ae->psgtab[j++]=13; + for (i=0;i<35;i++) ae->psgtab[j++]=14; + for (i=0;i<72;i++) ae->psgtab[j++]=15; + if (j!=256) { + rasm_printf(ae,"Internal error with PSG conversion table\n"); + exit(-44); + } + for (i=j=0;i<1;i++) ae->psgfine[j++]=0; + for (i=0;i<1;i++) ae->psgfine[j++]=1; + for (i=0;i<1;i++) ae->psgfine[j++]=2; + for (i=0;i<2;i++) ae->psgfine[j++]=3; + for (i=0;i<2;i++) ae->psgfine[j++]=4; + for (i=0;i<2;i++) ae->psgfine[j++]=5; + for (i=0;i<3;i++) ae->psgfine[j++]=6; + for (i=0;i<4;i++) ae->psgfine[j++]=7; + for (i=0;i<7;i++) ae->psgfine[j++]=8; + for (i=0;i<9;i++) ae->psgfine[j++]=9; + for (i=0;i<13;i++) ae->psgfine[j++]=10; + for (i=0;i<19;i++) ae->psgfine[j++]=11; + for (i=0;i<27;i++) ae->psgfine[j++]=12; + for (i=0;i<37;i++) ae->psgfine[j++]=13; + for (i=0;i<53;i++) ae->psgfine[j++]=14; + for (i=0;i<75;i++) ae->psgfine[j++]=15; + if (j!=256) { + rasm_printf(ae,"Internal error with PSG conversion table\n"); + exit(-44); + } + /* default var */ + ae->autorise_export=1; + ExpressionSetDicoVar(ae,"PI",3.1415926545); + ExpressionSetDicoVar(ae,"ASSEMBLER_RASM",1); + + /* add a fictive expression to simplify test when parsing expressions */ + ObjectArrayAddDynamicValueConcat((void **)&ae->expression,&ae->ie,&ae->me,&curexp,sizeof(curexp)); + + /* compute CRC for keywords and directives */ + for (icrc=0;instruction[icrc].mnemo[0];icrc++) instruction[icrc].crc=GetCRC(instruction[icrc].mnemo); + for (icrc=0;math_keyword[icrc].mnemo[0];icrc++) math_keyword[icrc].crc=GetCRC(math_keyword[icrc].mnemo); + + if (ae->as80==1) { /* not for UZ80 */ + for (icrc=0;instruction[icrc].mnemo[0];icrc++) { + if (strcmp(instruction[icrc].mnemo,"DEFB")==0 || strcmp(instruction[icrc].mnemo,"DB")==0) { + instruction[icrc].makemnemo=_DEFB_as80; + } else if (strcmp(instruction[icrc].mnemo,"DEFW")==0 || strcmp(instruction[icrc].mnemo,"DW")==0) { + instruction[icrc].makemnemo=_DEFW_as80; + } else if (strcmp(instruction[icrc].mnemo,"DEFI")==0) { + instruction[icrc].makemnemo=_DEFI_as80; + } + } + } + + for (icrc=0;instruction[icrc].mnemo[0];icrc++) { + /* get indexes for DEF instructions */ + if (strcmp(instruction[icrc].mnemo,"DEFB")==0) { + ICRC_DEFB=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DB")==0) { + ICRC_DB=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFW")==0) { + ICRC_DEFW=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DW")==0) { + ICRC_DW=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFR")==0) { + ICRC_DEFR=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DR")==0) { + ICRC_DR=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFS")==0) { + ICRC_DEFS=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DS")==0) { + ICRC_DS=icrc; + } else if (strcmp(instruction[icrc].mnemo,"DEFI")==0) { + ICRC_DEFI=icrc; + } + } + + /* Execution des mots clefs */ + /********************************************************** + A S S E M B L I N G M A I N L O O P + **********************************************************/ +#if TRACE_ASSEMBLE +printf("init ok\n"); +#endif +#if TRACE_GENERALE +printf("-loop\n"); +#endif + + ae->idx=1; + while (wordlist[ae->idx].t!=2) { + curcrc=GetCRC(wordlist[ae->idx].w); + /********************* + d e b u g i n f o + *********************/ + #if TRACE_ASSEMBLE + { + int iiii=0; + printf(KVERBOSE"%d [%s] L%d [%s]e=%d ",ae->idx,ae->filename[wordlist[ae->idx].ifile],wordlist[ae->idx].l,wordlist[ae->idx].w,wordlist[ae->idx].e); + while (!wordlist[ae->idx+iiii++].t) rasm_printf(ae," [%s]e=%d ",wordlist[ae->idx+iiii].w,wordlist[ae->idx+iiii].e); + + for (iiii=0;iiii<ae->imacropos;iiii++) { + printf("M[%d] s=%d e=%d ",iiii,ae->macropos[iiii].start,ae->macropos[iiii].end); + } + printf("\n"); + } + #endif + + /******************************************************************** + c o n d i t i o n n a l a s s e m b l y m a n a g e m e n t + ********************************************************************/ + if (ae->ii || ae->isw) { + /* inhibition of if/endif */ + for (inhibe=curii=0;curii<ae->ii;curii++) { + if (!ae->ifthen[curii].v || ae->ifthen[curii].v==-1) { + inhibe=1; + break; + } + } + /* when inhibited we are looking only for a IF/IFDEF/IFNOT/IFNDEF/ELSE/ELSEIF/ENDIF or SWITCH/CASE/DEFAULT/ENDSWITCH */ + if (inhibe) { + /* this section does NOT need to be agressively optimized !!! */ + if (curcrc==CRC_ELSEIF && strcmp(wordlist[ae->idx].w,"ELSEIF")==0) { + /* true IF needs to be done ONLY on the active level */ + if (curii==ae->ii-1) __ELSEIF(ae); else __ELSEIF_light(ae); + } else if (curcrc==CRC_ELSE && strcmp(wordlist[ae->idx].w,"ELSE")==0) { + __ELSE(ae); + } else if (curcrc==CRC_ENDIF && strcmp(wordlist[ae->idx].w,"ENDIF")==0) { + __ENDIF(ae); + } else if (curcrc==CRC_IF && strcmp(wordlist[ae->idx].w,"IF")==0) { + /* as we are inhibited we do not have to truly compute IF */ + __IF_light(ae); + } else if (curcrc==CRC_IFDEF && strcmp(wordlist[ae->idx].w,"IFDEF")==0) { + __IFDEF_light(ae); + } else if (curcrc==CRC_IFNOT && strcmp(wordlist[ae->idx].w,"IFNOT")==0) { + __IFNOT_light(ae); + } else if (curcrc==CRC_IFUSED && strcmp(wordlist[ae->idx].w,"IFUSED")==0) { + __IFUSED_light(ae); + } else if (curcrc==CRC_IFNUSED && strcmp(wordlist[ae->idx].w,"IFNUSED")==0) { + __IFNUSED_light(ae); + } else if (curcrc==CRC_IFNDEF && strcmp(wordlist[ae->idx].w,"IFNDEF")==0) { + __IFNDEF_light(ae); + } else if (curcrc==CRC_SWITCH && strcmp(wordlist[ae->idx].w,"SWITCH")==0) { + __SWITCH_light(ae); + } else if (curcrc==CRC_CASE && strcmp(wordlist[ae->idx].w,"CASE")==0) { + __CASE_light(ae); + } else if (curcrc==CRC_ENDSWITCH && strcmp(wordlist[ae->idx].w,"ENDSWITCH")==0) { + __ENDSWITCH(ae); + } else if (curcrc==CRC_BREAK && strcmp(wordlist[ae->idx].w,"BREAK")==0) { + __BREAK_light(ae); + } else if (curcrc==CRC_DEFAULT && strcmp(wordlist[ae->idx].w,"DEFAULT")==0) { + __DEFAULT_light(ae); + } + while (wordlist[ae->idx].t==0) ae->idx++; + ae->idx++; + continue; + } else { + /* inhibition of switch/case */ + for (curii=0;curii<ae->isw;curii++) { + if (!ae->switchcase[curii].execute) { + inhibe=2; + break; + } + } + if (inhibe) { + /* this section does NOT need to be agressively optimized !!! */ + if (curcrc==CRC_CASE && strcmp(wordlist[ae->idx].w,"CASE")==0) { + __CASE(ae); + } else if (curcrc==CRC_ENDSWITCH && strcmp(wordlist[ae->idx].w,"ENDSWITCH")==0) { + __ENDSWITCH(ae); + } else if (curcrc==CRC_IF && strcmp(wordlist[ae->idx].w,"IF")==0) { + /* as we are inhibited we do not have to truly compute IF */ + __IF_light(ae); + } else if (curcrc==CRC_IFDEF && strcmp(wordlist[ae->idx].w,"IFDEF")==0) { + __IFDEF(ae); + } else if (curcrc==CRC_IFNOT && strcmp(wordlist[ae->idx].w,"IFNOT")==0) { + __IFNOT(ae); + } else if (curcrc==CRC_ELSE && strcmp(wordlist[ae->idx].w,"ELSE")==0) { + __ELSE(ae); + } else if (curcrc==CRC_ENDIF && strcmp(wordlist[ae->idx].w,"ENDIF")==0) { + __ENDIF(ae); + } else if (curcrc==CRC_ELSEIF && strcmp(wordlist[ae->idx].w,"ELSEIF")==0) { + __ELSEIF(ae); + } else if (curcrc==CRC_IFUSED && strcmp(wordlist[ae->idx].w,"IFUSED")==0) { + __IFUSED(ae); + } else if (curcrc==CRC_IFNUSED && strcmp(wordlist[ae->idx].w,"IFNUSED")==0) { + __IFNUSED(ae); + } else if (curcrc==CRC_IFNDEF && strcmp(wordlist[ae->idx].w,"IFNDEF")==0) { + __IFNDEF(ae); + } else if (curcrc==CRC_SWITCH && strcmp(wordlist[ae->idx].w,"SWITCH")==0) { + __SWITCH(ae); + } else if (curcrc==CRC_BREAK && strcmp(wordlist[ae->idx].w,"BREAK")==0) { + __BREAK(ae); + } else if (curcrc==CRC_DEFAULT && strcmp(wordlist[ae->idx].w,"DEFAULT")==0) { + __DEFAULT(ae); + } + while (wordlist[ae->idx].t==0) ae->idx++; + ae->idx++; + continue; + } + } + } + if (ae->imacropos) { + /* are we still in a macro? */ + if (ae->idx>=ae->macropos[0].end) { + /* are we out of all repetition blocks? */ + if (!ae->ir && !ae->iw) { + ae->imacropos=0; + + /* quand on sort du local, on récupère le dernier label global */ + if (ae->lastsuperglobal!=ae->lastgloballabel && ae->lastsuperglobal) { + if (ae->lastglobalalloc) { + MemFree(ae->lastgloballabel); + ae->lastglobalalloc=0; + } + ae->lastgloballabel=ae->lastsuperglobal; + ae->lastgloballabellen=strlen(ae->lastgloballabel); + } + } + } + } + /***************************************** + e x e c u t e i n s t r u c t i o n + *****************************************/ + executed=0; + if ((ifast=ae->fastmatch[(int)wordlist[ae->idx].w[0]])!=-1) { + while (instruction[ifast].mnemo[0]==wordlist[ae->idx].w[0]) { + if (instruction[ifast].crc==curcrc && strcmp(instruction[ifast].mnemo,wordlist[ae->idx].w)==0) { +#if TRACE_ASSEMBLE +printf("-> mnemo\n"); +#endif + instruction[ifast].makemnemo(ae); + executed=1; + break; + } + ifast++; + } + } + /***************************************** + e x e c u t e m a c r o + *****************************************/ + if (!executed) { + /* is it a macro? */ + if ((ifast=SearchMacro(ae,curcrc,wordlist[ae->idx].w))>=0) { +#if TRACE_ASSEMBLE +printf("-> macro\n"); +#endif + wordlist=__MACRO_EXECUTE(ae,ifast); + continue; + } + } + /********************************************************************* + e x e c u t e e x p r e s s i o n o r p u s h l a b e l + *********************************************************************/ + if (!ae->stop) { + if (!executed) { + /* no instruction executed, this is a label or an assignement */ + if (wordlist[ae->idx].e) { +#if TRACE_ASSEMBLE +printf("-> expr\n"); +#endif + ExpressionFastTranslate(ae,&wordlist[ae->idx].w,0); + ComputeExpression(ae,wordlist[ae->idx].w,ae->codeadr,0,0); + } else { +#if TRACE_ASSEMBLE +printf("-> label\n"); +#endif + PushLabel(ae); + } + } else { +#if TRACE_ASSEMBLE +printf("-> ajuste IDX\n"); +#endif + while (!wordlist[ae->idx].t) { + ae->idx++; + } + } + ae->idx++; + } else { +#if TRACE_ASSEMBLE +printf("-> STOP\n"); +#endif + break; + } + } +#if TRACE_ASSEMBLE + rasm_printf(ae,KVERBOSE"%d [%s] L%d [%s] fin de la liste de mots\n",ae->idx,ae->filename[wordlist[ae->idx].ifile],wordlist[ae->idx].l,wordlist[ae->idx].w); + printf("check ORG\n"); +#endif +#if TRACE_GENERALE +printf("-check ORG\n"); +#endif + + if (!ae->stop) { + /* end of assembly, check there is no opened struct */ + if (ae->getstruct) { + MakeError(ae,ae->backup_filename,ae->backup_line,"STRUCT declaration was not closed\n"); + } + /* end of assembly, close the last ORG zone */ + if (ae->io) { + ae->orgzone[ae->io-1].memend=ae->outputadr; + } + OverWriteCheck(ae); + /* end of assembly, close crunched zone (if any) */ + __internal_UpdateLZBlockIfAny(ae); + + /* end of assembly, check for opened repeat and opened while loop */ + for (i=0;i<ae->ir;i++) { + MakeError(ae,ae->filename[wordlist[ae->repeat[i].start].ifile],wordlist[ae->repeat[i].start].l,"REPEAT was not closed\n"); + } + for (i=0;i<ae->iw;i++) { + MakeError(ae,ae->filename[wordlist[ae->whilewend[i].start].ifile],wordlist[ae->whilewend[i].start].l,"WHILE was not closed\n"); + } + /* is there any IF opened? -> need an evolution for a better error message */ + for (i=0;i<ae->ii;i++) { + char instr[32]; + switch (ae->ifthen[i].type) { + case E_IFTHEN_TYPE_IF:strcpy(instr,"IF");break; + case E_IFTHEN_TYPE_IFNOT:strcpy(instr,"IFNOT");break; + case E_IFTHEN_TYPE_IFDEF:strcpy(instr,"IFDEF");break; + case E_IFTHEN_TYPE_IFNDEF:strcpy(instr,"IFNDEF");break; + case E_IFTHEN_TYPE_ELSE:strcpy(instr,"ELSE");break; + case E_IFTHEN_TYPE_ELSEIF:strcpy(instr,"ELSEIF");break; + case E_IFTHEN_TYPE_IFUSED:strcpy(instr,"IFUSED");break; + case E_IFTHEN_TYPE_IFNUSED:strcpy(instr,"IFNUSED");break; + default:strcpy(instr,"<unknown>"); + } + MakeError(ae,ae->ifthen[i].filename,ae->ifthen[i].line,"%s conditionnal block was not closed\n",instr); + } + } +#if TRACE_ASSEMBLE +printf("crunch if any\n"); +#endif + /*************************************************** + c r u n c h L Z s e c t i o n s + ***************************************************/ + if (!ae->stop || !ae->nberr) { + for (i=0;i<ae->ilz;i++) { + /* compute labels and expression inside crunched blocks */ + PopAllExpression(ae,i); + + ae->curlz=i; + iorgzone=ae->lzsection[i].iorgzone; + ibank=ae->lzsection[i].ibank; + input_data=&ae->mem[ae->lzsection[i].ibank][ae->lzsection[i].memstart]; + input_size=ae->lzsection[i].memend-ae->lzsection[i].memstart; +//printf("grouik (%d) %s\n",ae->lzsection[i].lzversion,ae->lzsection[i].lzversion==8?"mizou":""); + if (!input_size) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: crunched section is empty\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + } else { + switch (ae->lzsection[i].lzversion) { + case 7: + #ifndef NO_3RD_PARTIES + lzdata=ZX7_compress(optimize(input_data, input_size), input_data, input_size, &slzlen); + lzlen=slzlen; + #endif + break; + case 4: + #ifndef NO_3RD_PARTIES + lzdata=LZ4_crunch(input_data,input_size,&lzlen); + #endif + break; + case 8: + #ifndef NO_3RD_PARTIES + rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",input_size/1024.0); + + lzdata=Exomizer_crunch(input_data,input_size,&lzlen); + #endif + break; + case 48: + lzdata=LZ48_crunch(input_data,input_size,&lzlen); + break; + case 49: + lzdata=LZ49_crunch(input_data,input_size,&lzlen); + break; + default: + rasm_printf(ae,"Internal error - unknown crunch method %d\n",ae->lzsection[i].lzversion); + exit(-12); + } + } + //rasm_printf(ae,"lzsection[%d] type=%d start=%04X end=%04X crunched size=%d\n",i,ae->lzsection[i].lzversion,ae->lzsection[i].memstart,ae->lzsection[i].memend,lzlen); + + if (input_size<lzlen) { + MakeError(ae,ae->filename[ae->wl[ae->lzsection[i].iw].ifile],ae->wl[ae->lzsection[i].iw].l,"As the LZ section cannot crunch data, Rasm may not guarantee assembled file!\n"); + } + + lzshift=lzlen-(ae->lzsection[i].memend-ae->lzsection[i].memstart); + if (lzshift>0) { + MemMove(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend+lzshift,ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend,65536-ae->lzsection[i].memend-lzshift); + } else if (lzshift<0) { + lzmove=ae->orgzone[iorgzone].memend-ae->lzsection[i].memend; + if (lzmove) { + MemMove(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend+lzshift,ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memend,lzmove); + } + } + memcpy(ae->mem[ae->lzsection[i].ibank]+ae->lzsection[i].memstart,lzdata,lzlen); + MemFree(lzdata); + /******************************************************************* + l a b e l a n d e x p r e s s i o n r e l o c a t i o n + *******************************************************************/ + /* relocate labels in the same ORG zone AND after the current crunched section */ + il=ae->lzsection[i].ilabel; + while (il<ae->il && ae->label[il].iorgzone==iorgzone && ae->label[il].ibank==ibank) { + curlabel=SearchLabel(ae,ae->label[il].iw!=-1?wordlist[ae->label[il].iw].w:ae->label[il].name,ae->label[il].crc); + /* CANNOT be NULL */ + curlabel->ptr+=lzshift; + //printf("label [%s] shifte de %d valeur #%04X -> #%04X\n",curlabel->iw!=-1?wordlist[curlabel->iw].w:curlabel->name,lzshift,curlabel->ptr-lzshift,curlabel->ptr); + il++; + } + /* relocate expressions in the same ORG zone AND after the current crunched section */ + il=ae->lzsection[i].iexpr; + while (il<ae->ie && ae->expression[il].iorgzone==iorgzone && ae->expression[il].ibank==ibank) { + ae->expression[il].wptr+=lzshift; + ae->expression[il].ptr+=lzshift; + //printf("expression [%s] shiftee ptr=#%04X wptr=#%04X\n", ae->expression[il].reference?ae->expression[il].reference:wordlist[ae->expression[il].iw].w, ae->expression[il].ptr, ae->expression[il].wptr); + il++; + } + /* relocate crunched sections in the same ORG zone AND after the current crunched section */ + il=i+1; + while (il<ae->ilz && ae->lzsection[il].iorgzone==iorgzone && ae->lzsection[il].ibank==ibank) { + //rasm_printf(ae,"reloger lzsection[%d] O%d B%d\n",il,ae->lzsection[il].iorgzone,ae->lzsection[il].ibank); + ae->lzsection[il].memstart+=lzshift; + ae->lzsection[il].memend+=lzshift; + il++; + } + /* relocate current ORG zone */ + ae->orgzone[iorgzone].memend+=lzshift; + } + if (ae->ilz) { + /* compute expression placed after the last crunched block */ + PopAllExpression(ae,ae->ilz); + } + /* compute expression outside crunched blocks */ + PopAllExpression(ae,-1); + } + +/*************************************************************************************************************************************************************************************** +**************************************************************************************************************************************************************************************** + W R I T E O U T P U T F I L E S +**************************************************************************************************************************************************************************************** +***************************************************************************************************************************************************************************************/ + TMP_filename=MemMalloc(PATH_MAX); +#if 0 +for (i=0;i<ae->io;i++) { +printf("ORG[%02d] start=%04X end=%04X ibank=%d nocode=%d protect=%d\n",i,ae->orgzone[i].memstart,ae->orgzone[i].memend,ae->orgzone[i].ibank,ae->orgzone[i].nocode,ae->orgzone[i].protect); +} +#endif +#if TRACE_ASSEMBLE +printf("output files\n"); +#endif + + if (!ae->nberr && !ae->checkmode) { + + /* enregistrement des fichiers programmes par la commande SAVE */ + PopAllSave(ae); + + if (ae->nbsave==0 || ae->forcecpr || ae->forcesnapshot) { + /********************************************* + ********************************************** + C A R T R I D G E + ********************************************** + *********************************************/ + if (ae->forcecpr) { + char ChunkName[32]; + int ChunkSize; + int do_it=1; + unsigned char chunk_endian; + + if (ae->cartridge_name) { + sprintf(TMP_filename,"%s",ae->cartridge_name); + } else { + sprintf(TMP_filename,"%s.cpr",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + rasm_printf(ae,KIO"Write cartridge file %s\n",TMP_filename); + for (i=maxrom=0;i<ae->io;i++) { + if (ae->orgzone[i].ibank<32 && ae->orgzone[i].ibank>maxrom) maxrom=ae->orgzone[i].ibank; + } + /* construction du CPR */ + /* header blablabla */ + strcpy(ChunkName,"RIFF"); + FileWriteBinary(TMP_filename,ChunkName,4); + ChunkSize=(maxrom+1)*(16384+8)+4; + chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + sprintf(ChunkName,"AMS!"); + FileWriteBinary(TMP_filename,ChunkName,4); + +// for (j=0;j<ae->io;j++) { +//printf("ORG[%03d]=B%02d/#%04X/#%04X\n",j,ae->orgzone[j].ibank,ae->orgzone[j].memstart,ae->orgzone[j].memend); +// } + for (i=0;i<=maxrom;i++) { + offset=65536; + endoffset=0; + for (j=0;j<ae->io;j++) { + if (ae->orgzone[j].protect) continue; /* protected zones exclusion */ + /* bank data may start anywhere (typically #0000 or #C000) */ + if (ae->orgzone[j].ibank==i && ae->orgzone[j].memstart!=ae->orgzone[j].memend) { + if (ae->orgzone[j].memstart<offset) offset=ae->orgzone[j].memstart; + if (ae->orgzone[j].memend>endoffset) endoffset=ae->orgzone[j].memend; + } + } + if (endoffset>offset) { + int lm=0; + if (ae->iwnamebank[i]>0) { + lm=strlen(ae->wl[ae->iwnamebank[i]].w)-2; + } + rasm_printf(ae,KVERBOSE"WriteCPR bank %2d of %5d byte%s start at #%04X",i,endoffset-offset,endoffset-offset>1?"s":" ",offset); + if (endoffset-offset>16384) { + rasm_printf(ae,"\nROM is too big!!!\n"); + FileWriteBinaryClose(TMP_filename); + FileRemoveIfExists(TMP_filename); + FreeAssenv(ae); + exit(ABORT_ERROR); + } + if (lm) { + rasm_printf(ae," (%-*.*s)\n",lm,lm,ae->wl[ae->iwnamebank[i]].w+1); + } else { + rasm_printf(ae,"\n"); + } + } else { + rasm_printf(ae,KVERBOSE"WriteCPR bank %2d (empty)\n",i); + } + ChunkSize=16384; + sprintf(ChunkName,"cb%02d",i); + FileWriteBinary(TMP_filename,ChunkName,4); + chunk_endian=ChunkSize&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>8)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>16)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + chunk_endian=(ChunkSize>>24)&0xFF;FileWriteBinary(TMP_filename,(char*)&chunk_endian,1); + if (offset>0xC000) { + unsigned char filler[16384]={0}; + ChunkSize=65536-offset; + if (ChunkSize) FileWriteBinary(TMP_filename,(char*)ae->mem[i]+offset,ChunkSize); + /* ADD zeros until the end of the bank */ + FileWriteBinary(TMP_filename,(char*)filler,16384-ChunkSize); + } else { + FileWriteBinary(TMP_filename,(char*)ae->mem[i]+offset,ChunkSize); + } + } + FileWriteBinaryClose(TMP_filename); + rasm_printf(ae,"Total %d bank%s (%dK)\n",maxrom+1,maxrom+1>1?"s":"",(maxrom+1)*16); + /********************************************* + ********************************************** + S N A P S H O T + ********************************************** + *********************************************/ + } else if (ae->forcesnapshot) { + + if (ae->forcezx) { + unsigned char zxsnapheader[0x1A]={0}; + + if (ae->snapshot_name) { + sprintf(TMP_filename,"%s",ae->snapshot_name); + } else { + sprintf(TMP_filename,"%s.sna",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + /* do we have a bankset? */ + /* zx bootstrap */ + zxsnapheader[0x13]=0; /* 0:DI 4:EI */ + zxsnapheader[0x17]=ae->zxsnapshot.stack&0xFF; + zxsnapheader[0x18]=(ae->zxsnapshot.stack>>8)&0xFF; + zxsnapheader[0x19]=1; /* IM 1 */ + + //ae->zxsnapshot.stack&=0xFFFF; + ae->mem[0][ae->zxsnapshot.stack]=ae->zxsnapshot.run&0xFF; + ae->mem[0][ae->zxsnapshot.stack+1]=(ae->zxsnapshot.run>>8)&0xFF; + + rasm_printf(ae,KIO"Write 48K ZX snapshot file %s\n",TMP_filename); + + /* header */ + FileWriteBinary(TMP_filename,(char *)&zxsnapheader,27); + /* data */ + if (ae->bankset[0]) { + FileWriteBinary(TMP_filename,(char *)ae->mem[0]+16384,16384*3); + } else { + FileWriteBinary(TMP_filename,(char *)ae->mem[5],16384); + FileWriteBinary(TMP_filename,(char *)ae->mem[2],16384); + FileWriteBinary(TMP_filename,(char *)ae->mem[0],16384); + } + FileWriteBinaryClose(TMP_filename); + } else { + unsigned char packed[65536]={0}; + unsigned char *rlebank=NULL; + char ChunkName[16]; + int ChunkSize; + int do_it=1; + int bankset; + int noflood=0; + + if (ae->snapshot.version==2 && ae->snapshot.CPCType>2) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"[%s:%d] Warning: V2 snapshot cannot select a Plus model (forced to 6128)\n",GetCurrentFile(ae),ae->wl[ae->idx].l); + ae->snapshot.CPCType=2; /* 6128 */ + } + + if (ae->snapshot_name) { + sprintf(TMP_filename,"%s",ae->snapshot_name); + } else { + sprintf(TMP_filename,"%s.sna",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + maxrom=-1; + for (i=0;i<ae->io;i++) { + if (ae->orgzone[i].ibank<BANK_MAX_NUMBER && ae->orgzone[i].ibank>maxrom && ae->orgzone[i].memstart!=ae->orgzone[i].memend) { + maxrom=ae->orgzone[i].ibank; + } + } + + //printf("maxrom=%d\n",maxrom); + /* construction du SNA */ + if (ae->snapshot.version==2) { + if (maxrom>=4) { + ae->snapshot.dumpsize[0]=128; + } else if (maxrom>=0) { + ae->snapshot.dumpsize[0]=64; + } + } + if (maxrom==-1) { + rasm_printf(ae,KWARNING"Warning: No byte were written in snapshot memory\n"); + } else { + rasm_printf(ae,KIO"Write snapshot v%d file %s\n",ae->snapshot.version,TMP_filename); + + /* header */ + FileWriteBinary(TMP_filename,(char *)&ae->snapshot,0x100); + /* write all memory crunched */ + for (i=0;i<=maxrom;i+=4) { + bankset=i>>2; + if (ae->bankset[bankset]) { + memcpy(packed,ae->mem[i],65536); + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d,%d,%d,%d packed\n",i,i+1,i+2,i+3); + else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} + } else { + memset(packed,0,65536); + for (k=0;k<4;k++) { + offset=65536; + endoffset=0; + for (j=0;j<ae->io;j++) { + if (ae->orgzone[j].protect) continue; /* protected zones exclusion */ + /* bank data may start anywhere (typically #0000 or #C000) */ + if (ae->orgzone[j].ibank==i+k && ae->orgzone[j].memstart!=ae->orgzone[j].memend) { + if (ae->orgzone[j].memstart<offset) offset=ae->orgzone[j].memstart; + if (ae->orgzone[j].memend>endoffset) endoffset=ae->orgzone[j].memend; + } + } + if (endoffset-offset>16384) { + rasm_printf(ae,KERROR"\nBANK is too big!!!\n"); + FileWriteBinaryClose(TMP_filename); + FileRemoveIfExists(TMP_filename); + FreeAssenv(ae); + exit(ABORT_ERROR); + } + /* banks are gathered in the 64K block */ + if (offset>0xC000) { + ChunkSize=65536-offset; + memcpy(packed+k*16384,(char*)ae->mem[i+k]+offset,ChunkSize); + } else { + memcpy(packed+k*16384,(char*)ae->mem[i+k]+offset,16384); + } + + if (endoffset>offset) { + int lm=0; + if (ae->iwnamebank[i]>0) { + lm=strlen(ae->wl[ae->iwnamebank[i]].w)-2; + } + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d of %5d byte%s start at #%04X",i+k,endoffset-offset,endoffset-offset>1?"s":" ",offset); + else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} + if (endoffset-offset>16384) { + rasm_printf(ae,KERROR"\nRAM block is too big!!!\n"); + FileWriteBinaryClose(TMP_filename); + FileRemoveIfExists(TMP_filename); + FreeAssenv(ae); + exit(ABORT_ERROR); + } + if (lm) { + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE" (%-*.*s)\n",lm,lm,ae->wl[ae->iwnamebank[i+k]].w+1); + } else { + if (i<4 || i+4>maxrom) rasm_printf(ae,"\n"); + } + } else { + if (i<4 || i+4>maxrom) rasm_printf(ae,KVERBOSE"WriteSNA bank %2d (empty)\n",i+k); + else if (!noflood) {rasm_printf(ae,KVERBOSE"[...]\n");noflood=1;} + } + } + } + + if (ae->snapshot.version==2) { + /* snapshot v2 */ + FileWriteBinary(TMP_filename,(char*)&packed,65536); + if (bankset) { + /* v2 snapshot is 128K maximum */ + maxrom=7; + break; + } + } else { + /* compression par défaut avec snapshot v3 */ + rlebank=EncodeSnapshotRLE(packed,&ChunkSize); + + if (bankset>=0 && bankset<=8) { + sprintf(ChunkName,"MEM%d",bankset); + } else if (bankset>8 && bankset<=0x40) { + /* extended chunk for 4M extension -> MX09 to MX40 (hexa numbered) */ + sprintf(ChunkName,"MX%02X",bankset); + } else { + MakeError(ae,"(core)",0,"internal error during snapshot write, please report (%d)\n",bankset); + } + + FileWriteBinary(TMP_filename,ChunkName,4); + if (rlebank!=NULL) { + FileWriteBinary(TMP_filename,(char*)&ChunkSize,4); + FileWriteBinary(TMP_filename,(char*)rlebank,ChunkSize); + MemFree(rlebank); + } else { + ChunkSize=65536; + FileWriteBinary(TMP_filename,(char*)&packed,ChunkSize); + } + } + } + + /************************************************************** + snapshot additional chunks in v3+ only + **************************************************************/ + if (ae->snapshot.version>=3) { + /* export breakpoint */ + if (ae->export_snabrk) { + /* BRKS chunk for Winape emulator (unofficial) + + 2 bytes - adress + 1 byte - 0=base 64K / 1=extended + 2 bytes - condition (zeroed) + */ + struct s_breakpoint breakpoint={0}; + unsigned char *brkschunk=NULL; + unsigned int idx=8; + + /* add labels and local labels to breakpoint pool (if any) */ + for (i=0;i<ae->il;i++) { + if (!ae->label[i].name) { + if (strncmp(ae->wl[ae->label[i].iw].w,"BRK",3)==0) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } else { + if (strncmp(ae->label[i].name,"@BRK",4)==0 || strstr(ae->label[i].name,".BRK")) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } + } + + brkschunk=MemMalloc(ae->ibreakpoint*5+8); + strcpy((char *)brkschunk,"BRKS"); + + for (i=0;i<ae->ibreakpoint;i++) { + brkschunk[idx++]=ae->breakpoint[i].address&0xFF; + brkschunk[idx++]=(ae->breakpoint[i].address&0xFF00)/256; + brkschunk[idx++]=ae->breakpoint[i].bank; + brkschunk[idx++]=0; + brkschunk[idx++]=0; + } + + idx-=8; + brkschunk[4]=idx&0xFF; + brkschunk[5]=(idx>>8)&0xFF; + brkschunk[6]=(idx>>16)&0xFF; + brkschunk[7]=(idx>>24)&0xFF; + FileWriteBinary(TMP_filename,(char*)brkschunk,idx+8); // 8 bytes for the chunk header + MemFree(brkschunk); + + + /* BRKC chunk for ACE emulator + minimal integration + */ + brkschunk=MemMalloc(ae->ibreakpoint*256); + strcpy((char *)brkschunk,"BRKC"); + idx=8; + + for (i=0;i<ae->ibreakpoint;i++) { + brkschunk[idx++]=0; /* 0:Execution */ + brkschunk[idx++]=0; + brkschunk[idx++]=0; + brkschunk[idx++]=0; + brkschunk[idx++]=ae->breakpoint[i].address&0xFF; + brkschunk[idx++]=(ae->breakpoint[i].address&0xFF00)/256; + for (j=0;j<2+1+1+2+4+128;j++) { + brkschunk[idx++]=0; + } + sprintf((char *)brkschunk+idx,"breakpoint%d",i); /* breakpoint user name? */ + idx+=64+8; + } + idx-=8; + brkschunk[4]=idx&0xFF; + brkschunk[5]=(idx>>8)&0xFF; + brkschunk[6]=(idx>>16)&0xFF; + brkschunk[7]=(idx>>24)&0xFF; + FileWriteBinary(TMP_filename,(char *)brkschunk,idx+8); // 8 bytes for the chunk header + MemFree(brkschunk); + } + /* export optionnel des symboles */ + if (ae->export_sna) { + /* SYMB chunk for ACE emulator + + 1 byte - name size + n bytes - name (without 0 to end the string) + 6 bytes - reserved for future use + 2 bytes - shitty big endian adress for the symbol + */ + + unsigned char *symbchunk=NULL; + unsigned int idx=8; + int symbol_len; + + symbchunk=MemMalloc(8+ae->il*(1+255+6+2)); + strcpy((char *)symbchunk,"SYMB"); + + for (i=0;i<ae->il;i++) { + if (!ae->label[i].name) { + symbol_len=strlen(ae->wl[ae->label[i].iw].w); + if (symbol_len>255) symbol_len=255; + symbchunk[idx++]=symbol_len; + memcpy(symbchunk+idx,ae->wl[ae->label[i].iw].w,symbol_len); + idx+=symbol_len; + memset(symbchunk+idx,0,6); + idx+=6; + symbchunk[idx++]=(ae->label[i].ptr&0xFF00)/256; + symbchunk[idx++]=ae->label[i].ptr&0xFF; + } else { + if (ae->export_local || !ae->label[i].local) { + symbol_len=strlen(ae->label[i].name); + if (symbol_len>255) symbol_len=255; + symbchunk[idx++]=symbol_len; + memcpy(symbchunk+idx,ae->label[i].name,symbol_len); + idx+=symbol_len; + memset(symbchunk+idx,0,6); + idx+=6; + symbchunk[idx++]=(ae->label[i].ptr&0xFF00)/256; + symbchunk[idx++]=ae->label[i].ptr&0xFF; + } + } + } + if (ae->export_var) { + unsigned char *subchunk=NULL; + int retidx=0; + /* var are part of fast tree search structure */ + subchunk=SnapshotDicoTree(ae,&retidx); + if (retidx) { + symbchunk=MemRealloc(symbchunk,idx+retidx); + memcpy(symbchunk+idx,subchunk,retidx); + idx+=retidx; + SnapshotDicoInsert("FREE",0,&retidx); + } + } + if (ae->export_equ) { + symbchunk=MemRealloc(symbchunk,idx+ae->ialias*(1+255+6+2)); + + for (i=0;i<ae->ialias;i++) { + int tmpptr; + symbol_len=strlen(ae->alias[i].alias); + if (symbol_len>255) symbol_len=255; + symbchunk[idx++]=symbol_len; + memcpy(symbchunk+idx,ae->alias[i].alias,symbol_len); + idx+=symbol_len; + memset(symbchunk+idx,0,6); + idx+=6; + tmpptr=RoundComputeExpression(ae,ae->alias[i].translation,0,0,0); + symbchunk[idx++]=(tmpptr&0xFF00)/256; + symbchunk[idx++]=tmpptr&0xFF; + } + } + idx-=8; + symbchunk[4]=idx&0xFF; + symbchunk[5]=(idx>>8)&0xFF; + symbchunk[6]=(idx>>16)&0xFF; + symbchunk[7]=(idx>>24)&0xFF; + FileWriteBinary(TMP_filename,(char*)symbchunk,idx+8); // 8 bytes for the chunk header + } + } else { + if (ae->export_snabrk) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: breakpoint export is not supported with snapshot version 2\n"); + } + if (ae->export_sna) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: symbol export is not supported with snapshot version 2\n"); + } + } + + FileWriteBinaryClose(TMP_filename); + maxrom=(maxrom>>2)*4+4; + rasm_printf(ae,KAYGREEN"Total %d bank%s (%dK)\n",maxrom,maxrom>1?"s":"",(maxrom)*16); + } + } + /********************************************* + ********************************************** + B I N A R Y F I L E + ********************************************** + *********************************************/ + } else { + int lastspaceid=-1; + + if (ae->binary_name) { + sprintf(TMP_filename,"%s",ae->binary_name); + } else { + sprintf(TMP_filename,"%s.bin",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + /* en mode binaire classique on va recherche le dernier espace mémoire dans lequel on a travaillé qui n'est pas en 'nocode' */ + for (i=0;i<ae->io;i++) { + /* uniquement si le ORG a ete suivi d'ecriture */ + if (ae->orgzone[i].memstart!=ae->orgzone[i].memend && ae->orgzone[i].nocode!=1) { + lastspaceid=ae->orgzone[i].ibank; + } + } + if (lastspaceid!=-1) { + for (i=0;i<ae->io;i++) { + if (ae->orgzone[i].protect) continue; /* protected zones exclusion */ + /* uniquement si le ORG a ete suivi d'ecriture et n'est pas en 'nocode' */ + if (ae->orgzone[i].ibank==lastspaceid && ae->orgzone[i].memstart!=ae->orgzone[i].memend && ae->orgzone[i].nocode!=1) { + if (ae->orgzone[i].memstart<minmem) minmem=ae->orgzone[i].memstart; + if (ae->orgzone[i].memend>maxmem) maxmem=ae->orgzone[i].memend; + } + } + } + if (maxmem-minmem<=0) { + if (!ae->stop) { + if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: Not a single byte to output\n"); + } + if (ae->flux) { + *lenout=0; + } + } else { + if (!ae->flux) { + rasm_printf(ae,KIO"Write binary file %s (%d byte%s)\n",TMP_filename,maxmem-minmem,maxmem-minmem>1?"s":""); + if (ae->amsdos) { + AmsdosHeader=MakeAMSDOSHeader(minmem,minmem,maxmem,TMP_filename); //@@TODO + FileWriteBinary(TMP_filename,(char *)AmsdosHeader,128); + } + if (maxmem-minmem>0) { + FileWriteBinary(TMP_filename,(char*)ae->mem[lastspaceid]+minmem,maxmem-minmem); + FileWriteBinaryClose(TMP_filename); + } else { + if (ae->amsdos) { + FileWriteBinaryClose(TMP_filename); + } + } + } else { + *dataout=MemMalloc(maxmem-minmem+1); + memcpy(*dataout,ae->mem[lastspaceid]+minmem,maxmem-minmem); + *lenout=maxmem-minmem; + } + } + } + } + /******************************** + ********************************* + U N U S E D W A R N I N G + ********************************* + ********************************/ + if (ae->warn_unused) { + for (i=0;i<ae->ialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + if (!ae->alias[i].used) { + rasm_printf(ae,KWARNING"[%s:%d] Warning: alias %s declared but not used\n",ae->filename[ae->wl[ae->alias[i].iw].ifile],ae->wl[ae->alias[i].iw].l,ae->alias[i].alias); + } + } + } + WarnLabelTree(ae); + WarnDicoTree(ae); + } + + /**************************** + ***************************** + S Y M B O L E X P O R T + ***************************** + ****************************/ + if (ae->export_sym && !ae->export_sna) { + char *SymbolFileName; + SymbolFileName=MemMalloc(PATH_MAX); + +#define MAKE_SYMBOL_NAME if (ae->symbol_name) {sprintf(TMP_filename,"%s",ae->symbol_name);} else {sprintf(TMP_filename,"%s.sym",ae->outputfilename);} + + MAKE_SYMBOL_NAME + FileRemoveIfExists(TMP_filename); + + if (ae->export_multisym) { + /* multi-remove before writes */ + for (i=0;i<ae->nbbank;i++) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,i); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,i); + } + FileRemoveIfExists(TMP_filename); + } + rasm_printf(ae,KIO"Write symbol files %s.bank*\n",TMP_filename); + } else { + rasm_printf(ae,KIO"Write symbol file %s\n",TMP_filename); + } + + switch (ae->export_sym) { + case 5: + /* ZX export */ + for (i=0;i<ae->il;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + + if (!ae->label[i].name) { + sprintf(symbol_line,"%d:%04X %s\n",ae->label[i].ibank,ae->label[i].ptr,ae->wl[ae->label[i].iw].w); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,"%d:%04X %s\n",ae->label[i].ibank,ae->label[i].ptr,ae->label[i].name); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + FileWriteLineClose(TMP_filename); + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s %04X"); + } + if (ae->export_equ) { + for (i=0;i<ae->ialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,"%04X %s\n",RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0),ae->alias[i].alias); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + break; + case 4: + /* flexible */ + for (i=0;i<ae->il;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + + if (!ae->label[i].name) { + sprintf(symbol_line,ae->flexible_export,ae->wl[ae->label[i].iw].w,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,ae->flexible_export,ae->label[i].name,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,ae->flexible_export); + } + if (ae->export_equ) { + for (i=0;i<ae->ialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,ae->flexible_export,ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 3: + /* winape */ + for (i=0;i<ae->il;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + if (!ae->label[i].name) { + sprintf(symbol_line,"%s #%04X\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,"%s #%04X\n",ae->label[i].name,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s #%04X\n"); + } + if (ae->export_equ) { + for (i=0;i<ae->ialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,"%s #%04X\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 2: + /* pasmo */ + for (i=0;i<ae->il;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + if (!ae->label[i].name) { + sprintf(symbol_line,"%s EQU 0%04XH\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local || !ae->label[i].local) { + sprintf(symbol_line,"%s EQU 0%04XH\n",ae->label[i].name,ae->label[i].ptr); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s EQU 0%04XH\n"); + } + if (ae->export_equ) { + for (i=0;i<ae->ialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY")) { + sprintf(symbol_line,"%s EQU 0%04XH\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 1: + /* Rasm */ + for (i=0;i<ae->il;i++) { + if (ae->label[i].autorise_export) { + if (ae->export_multisym) { + if (ae->symbol_name) { + sprintf(TMP_filename,"%s.bank%d",ae->symbol_name,ae->label[i].ibank); + } else { + sprintf(TMP_filename,"%s.sym.bank%d",ae->outputfilename,ae->label[i].ibank); + } + } + if (!ae->label[i].name) { + sprintf(symbol_line,"%s #%X B%d\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); + FileWriteLine(TMP_filename,symbol_line); + } else { + if (ae->export_local) { + sprintf(symbol_line,"%s #%X B%d\n",ae->label[i].name,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + } + MAKE_SYMBOL_NAME + if (ae->export_var) { + /* var are part of fast tree search structure */ + ExportDicoTree(ae,TMP_filename,"%s #%X B0\n"); + } + if (ae->export_equ) { + for (i=0;i<ae->ialias;i++) { + if (strcmp(ae->alias[i].alias,"IX") && strcmp(ae->alias[i].alias,"IY") && ae->alias[i].autorise_export) { + sprintf(symbol_line,"%s #%X B0\n",ae->alias[i].alias,RoundComputeExpression(ae,ae->alias[i].translation,0,-ae->alias[i].iw,0)); + FileWriteLine(TMP_filename,symbol_line); + } + } + } + FileWriteLineClose(TMP_filename); + break; + case 0: + default:break; + } + MemFree(SymbolFileName); + } + /********************************* + ********************************** + B R E A K P O I N T S + ********************************** + *********************************/ + if (ae->export_brk) { + struct s_breakpoint breakpoint={0}; + + if (ae->breakpoint_name) { + sprintf(TMP_filename,"%s",ae->breakpoint_name); + } else { + sprintf(TMP_filename,"%s.brk",ae->outputfilename); + } + FileRemoveIfExists(TMP_filename); + + /* add labels and local labels to breakpoint pool (if any) */ + for (i=0;i<ae->il;i++) { + if (!ae->label[i].name) { + if (strncmp(ae->wl[ae->label[i].iw].w,"BRK",3)==0) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } else { + if (strncmp(ae->label[i].name,"@BRK",4)==0) { + breakpoint.address=ae->label[i].ptr; + if (ae->label[i].ibank>3) breakpoint.bank=1; else breakpoint.bank=0; + ObjectArrayAddDynamicValueConcat((void **)&ae->breakpoint,&ae->ibreakpoint,&ae->maxbreakpoint,&breakpoint,sizeof(struct s_breakpoint)); + } + } + } + + if (ae->ibreakpoint) { + rasm_printf(ae,KIO"Write breakpoint file %s\n",TMP_filename); + for (i=0;i<ae->ibreakpoint;i++) { + sprintf(symbol_line,"#%04X\n",ae->breakpoint[i].address); + FileWriteLine(TMP_filename,symbol_line); + } + FileWriteLineClose(TMP_filename); + } else { + if (!ae->nowarning) rasm_printf(ae,KWARNING"Warning: no breakpoint to output (previous file [%s] deleted anyway)\n",TMP_filename); + } + } + + } else { + if (!ae->dependencies) rasm_printf(ae,KERROR"%d error%s\n",ae->nberr,ae->nberr>1?"s":""); + } +#if TRACE_ASSEMBLE +printf("dependencies\n"); +#endif +/******************************************************************************************* + E X P O R T D E P E N D E N C I E S +*******************************************************************************************/ + if (ae->dependencies) { + int trigdep=0; + + /* depends ALL */ + if (ae->outputfilename && strcmp(ae->outputfilename,"rasmoutput")) { + trigdep=1; + printf("%s",ae->outputfilename); + if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); + } + for (i=1;i<ae->ifile;i++) { + trigdep=1; + SimplifyPath(ae->filename[i]); + printf("%s",ae->filename[i]); + if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); + } + for (i=0;i<ae->ih;i++) { + trigdep=1; + SimplifyPath(ae->hexbin[i].filename); + printf("%s",ae->hexbin[i].filename); + if (ae->dependencies==E_DEPENDENCIES_MAKE) printf(" "); else printf("\n"); + } + if (ae->dependencies==E_DEPENDENCIES_MAKE && trigdep) printf("\n"); + } + +/******************************************************************************************* + V E R B O S E S H I T +*******************************************************************************************/ +#if TRACE_ASSEMBLE + rasm_printf(ae,KVERBOSE"------ statistics ------------------\n"); + rasm_printf(ae,KVERBOSE"%d file%s\n",ae->ifile,ae->ifile>1?"s":""); + rasm_printf(ae,KVERBOSE"%d binary include%s\n",ae->ih,ae->ih>1?"s":""); + rasm_printf(ae,KVERBOSE"%d word%s\n",ae->nbword-1,ae->nbword>2?"s":""); + rasm_printf(ae,KVERBOSE"%d label%s\n",ae->il,ae->il>1?"s":""); + rasm_printf(ae,KVERBOSE"%d struct%s\n",ae->irasmstruct,ae->irasmstruct>1?"s":""); + rasm_printf(ae,KVERBOSE"%d var%s\n",ae->idic,ae->idic>1?"s":""); + rasm_printf(ae,KVERBOSE"%d expression%s\n",ae->ie,ae->ie>1?"s":""); + rasm_printf(ae,KVERBOSE"%d macro%s\n",ae->imacro,ae->imacro>1?"s":""); + rasm_printf(ae,KVERBOSE"%d alias%s\n",ae->ialias,ae->ialias>1?"s":""); + rasm_printf(ae,KVERBOSE"%d ORG zone%s\n",ae->io-1,ae->io>2?"s":""); + rasm_printf(ae,KVERBOSE"%d virtual space%s\n",ae->nbbank,ae->nbbank>1?"s":""); +#endif + +/******************************************************************************************* + C L E A N U P +*******************************************************************************************/ +#if TRACE_ASSEMBLE +printf("cleanup\n"); +#endif +#if TRACE_GENERALE +printf("-cleanup\n"); +#endif + if (TMP_filename) MemFree(TMP_filename); + if (ae->nberr) { + ok=-1; + if (ae->flux && *dataout) { + MemFree(*dataout); + *dataout=NULL; + } + if (lenout) *lenout=0; + } else { + ok=0; + } + + FreeAssenv(ae); +#if TRACE_ASSEMBLE +printf("end of assembling\n"); +#endif +#if TRACE_GENERALE +printf("-end ok=%d\n",ok); +#endif + return ok; +} + + +void EarlyPrepSrc(struct s_assenv *ae, char **listing, char *filename) { + int l,idx,c,quote_type=0; + int mlc_start,mlc_idx; + + /* virer les commentaires en ;, // mais aussi multi-lignes et convertir les decalages, passer les chars en upper case */ + l=idx=0; + while (listing[l]) { + c=listing[l][idx++]; + + if (!c) { + l++; + idx=0; + continue; + } else if (!quote_type) { + /* upper case */ + if (c>='a' && c<='z') { + listing[l][idx-1]=c=c-'a'+'A'; + } + + if (c=='\'' && idx>2 && strncmp(&listing[l][idx-3],"AF'",3)==0) { + /* il ne faut rien faire */ + } else if (c=='"' || c=='\'') { + quote_type=c; + } else if (c==';' || (c=='/' && listing[l][idx]=='/')) { + idx--; + while (listing[l][idx] && listing[l][idx]!=0x0D && listing[l][idx]!=0x0A) listing[l][idx++]=':'; + idx--; + } else if (c=='>' && listing[l][idx]=='>' && !quote_type) { + listing[l][idx-1]=']'; + listing[l][idx++]=' '; + continue; + } else if (c=='<' && listing[l][idx]=='<' && !quote_type) { + listing[l][idx-1]='['; + listing[l][idx++]=' '; + continue; + } else if (c=='/' && listing[l][idx]=='*' && !quote_type) { + /* multi-line comment */ + mlc_start=l; + mlc_idx=idx-1; + idx++; + while (1) { + c=listing[l][idx++]; + if (!c) { + idx=0; + l++; + if (!listing[l]) { + MakeError(ae,GetCurrentFile(ae),ae->wl[ae->idx].l,"opened comment to the end of the file\n",filename,l+1); + return; + } + } else if (c=='*' && listing[l][idx]=='/') { + idx++; + break; + } + } + /* merge */ + if (mlc_start==l) { + /* on the same line */ + while (mlc_idx<idx) listing[l][mlc_idx++]=' '; /* raz with spaces */ + } else { + /* multi-line */ + listing[mlc_start][mlc_idx]=0; /* raz EOL */ + mlc_start++; + while (mlc_start<l) listing[mlc_start++][0]=0; /* raz line */ + mlc_idx=0; + while (mlc_idx<idx) listing[l][mlc_idx++]=' '; /* raz beginning of the line */ + } + } + } else { + /* in quote */ + if (c=='\\') { + if (listing[l][idx]) { + idx++; + } + } else if (c==quote_type) { + quote_type=0; + } + } + } +} + +void PreProcessingSplitListing(struct s_listing **listing, int *il, int *ml, int idx, int end, int start) +{ + #undef FUNC + #define FUNC "PreProcessingSplitListing" + + struct s_listing curlisting={0}; + + /* split current line because there will be "before" include and "after include" line */ + ObjectArrayAddDynamicValueConcat((void**)listing,il,ml,&curlisting,sizeof(curlisting)); + MemMove(&((*listing)[idx+2]),&((*listing)[idx+1]),(*il-idx-2)*sizeof(struct s_listing)); + (*listing)[idx+1].ifile=(*listing)[idx].ifile; + (*listing)[idx+1].iline=(*listing)[idx].iline; + if ((*listing)[idx].listing[start]) { + (*listing)[idx+1].listing=TxtStrDup((*listing)[idx].listing+start); + } else { + (*listing)[idx+1].listing=TxtStrDup(";"); + } + strcpy((*listing)[idx].listing+end,":"); +} + +void PreProcessingInsertListing(struct s_listing **reflisting, int *il, int *ml, int idx, char **zelines, int ifile) +{ + #undef FUNC + #define FUNC "PreProcessingSplitListing" + + struct s_listing *listing; + int nbinsert,li,bil; + for (li=nbinsert=0;zelines[li];li++) nbinsert++; + bil=*il; + if (*il+nbinsert>=*ml) { + *il=*ml=*il+nbinsert; + *reflisting=MemRealloc(*reflisting,sizeof(struct s_listing)*(*ml)); + } else { + *il=*il+nbinsert; + } + listing=*reflisting; + MemMove(&listing[idx+1+nbinsert],&listing[idx+1],(bil-idx-1)*sizeof(struct s_listing)); + + for (li=0;zelines[li];li++) { + listing[idx+1+li].ifile=ifile; + listing[idx+1+li].iline=li+1; + listing[idx+1+li].listing=zelines[li]; + } +} + +int cmpkeyword(const void * a, const void * b) +{ + struct s_asm_keyword *sa,*sb; + sa=(struct s_asm_keyword *)a; + sb=(struct s_asm_keyword *)b; + return strcmp(sa->mnemo,sb->mnemo); +} + +struct s_assenv *PreProcessing(char *filename, int flux, const char *datain, int datalen, struct s_parameter *param) +{ + #undef FUNC + #define FUNC "PreProcessing" + + #define CharWord "@ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.=_($)][+-*/^%#|&'\"\\m}{[]" + + struct s_assenv *ae=NULL; + struct s_wordlist curw={0}; + struct s_wordlist *wordlist=NULL; + int nbword=0,maxword=0; + char **zelines=NULL; + + char *filename_toread; + + struct s_macro_fast *MacroFast=NULL; + int idxmacrofast=0,maxmacrofast=0; + + struct s_listing *listing=NULL; + struct s_listing curlisting; + int ilisting=0,maxlisting=0; + + char **listing_include=NULL; + int i,j,l=0,idx=0,c=0,li,le; + char Automate[256]={0}; + struct s_hexbin curhexbin; + char *newlistingline=NULL; + unsigned char *newdata; + struct s_label curlabel={0}; + char *labelsep1; + char **labelines=NULL; + /* state machine buffer */ + unsigned char *mem=NULL; + char *w=NULL,*wtmp=NULL; + int lw=0,mw=256; + char *bval=NULL; + int ival=0,sval=256; + char *qval=NULL; + int iqval=0,sqval=256; + struct s_repeat_index *TABrindex=NULL; + struct s_repeat_index *TABwindex=NULL; + struct s_repeat_index rindex={0}; + struct s_repeat_index windex={0}; + int nri=0,mri=0,ri=0; + int nwi=0,mwi=0,wi=0; + /* state machine trigger */ + int waiting_quote=0,lquote; + int macro_trigger=0; + int escape_code=0; + int quote_type=0; + int incbin=0,include=0,crunch=0; + int rewrite=0,hadcomma=0; + int nbinstruction; + int ifast,texpr; + int ispace=0; + +#if TRACE_GENERALE +printf("*** preprocessing ***\n"); +#endif + +#if TRACE_PREPRO +printf("start prepro, alloc assenv\n"); +#endif + + windex.cl=-1; + windex.cidx=-1; + rindex.cl=-1; + rindex.cidx=-1; + +#if TRACE_PREPRO +printf("malloc\n"); +#endif + ae=MemMalloc(sizeof(struct s_assenv)); +#if TRACE_PREPRO +printf("memset\n"); +#endif + memset(ae,0,sizeof(struct s_assenv)); + +#if TRACE_PREPRO +printf("paramz 1\n"); +#endif + if (param) { + ae->export_local=param->export_local; + ae->export_sym=param->export_sym; + ae->export_var=param->export_var; + ae->export_equ=param->export_equ; + ae->export_sna=param->export_sna; + ae->export_snabrk=param->export_snabrk; + if (param->export_sna || param->export_snabrk) { + ae->forcesnapshot=1; + } + ae->export_brk=param->export_brk; + ae->warn_unused=param->warn_unused; + ae->edskoverwrite=param->edskoverwrite; + ae->rough=param->rough; + ae->as80=param->as80; + ae->dams=param->dams; + ae->macrovoid=param->macrovoid; + if (param->v2) { + ae->forcesnapshot=1; + ae->snapshot.version=2; + } else { + ae->snapshot.version=3; + } + ae->maxerr=param->maxerr; + ae->extended_error=param->extended_error; + ae->nowarning=param->nowarning; + ae->breakpoint_name=param->breakpoint_name; + ae->symbol_name=param->symbol_name; + ae->binary_name=param->binary_name; + ae->flexible_export=param->flexible_export; + ae->cartridge_name=param->cartridge_name; + ae->snapshot_name=param->snapshot_name; + ae->checkmode=param->checkmode; + if (param->rough) ae->maxam=0; else ae->maxam=1; + /* additional symbols */ + for (i=0;i<param->nsymb;i++) { + char *sep; + sep=strchr(param->symboldef[i],'='); + if (sep) { + *sep=0; + ExpressionSetDicoVar(ae,param->symboldef[i],atof(sep+1)); + } + } + if (param->msymb) { + MemFree(param->symboldef); + param->nsymb=param->msymb=0; + } + /* include paths */ + ae->includepath=param->pathdef; + ae->ipath=param->npath; + ae->mpath=param->mpath; + /* old inline params */ + ae->dependencies=param->dependencies; + } +#if TRACE_PREPRO +printf("init 0\n"); +#endif +#if TRACE_GENERALE +printf("-init\n"); +#endif + /* generic init */ + ae->ctx1.maxivar=1; + ae->ctx2.maxivar=1; + ae->computectx=&ae->ctx1; + ae->flux=flux; + /* check snapshot structure */ + if (sizeof(ae->snapshot)!=0x100 || &ae->snapshot.fdd.motorstate-(unsigned char*)&ae->snapshot!=0x9C || &ae->snapshot.crtcstate.model-(unsigned char*)&ae->snapshot!=0xA4 + || &ae->snapshot.romselect-(unsigned char*)&ae->snapshot!=0x55 + || &ae->snapshot.interruptrequestflag-(unsigned char*)&ae->snapshot!=0xB4 + || &ae->snapshot.CPCType-(unsigned char*)&ae->snapshot!=0x6D) { + rasm_printf(ae,"snapshot structure integrity check KO\n"); + exit(349); + } + + for (i=0;i<4;i++) { + ae->bankgate[i]=0x7FC0; /* video memory has no paging */ + ae->setgate[i]=0x7FC0; /* video memory has no paging */ + } + for (i=0;i<256;i++) { + /* 4M expansion support on lower gate array port */ + ae->bankgate[i+4]=0x7FC4+(i&3)+((i&31)>>2)*8-0x100*(i>>5); + ae->setgate[i+4] =0x7FC2 +((i&31)>>2)*8-0x100*(i>>5); + //printf("%04X %04X\n",ae->bankgate[i+4],ae->setgate[i+4]); + } + + memcpy(ae->snapshot.idmark,"MV - SNA",8); + ae->snapshot.registers.IM=1; + + ae->snapshot.gatearray.palette[0]=0x04; + ae->snapshot.gatearray.palette[1]=0x0A; + ae->snapshot.gatearray.palette[2]=0x15; + ae->snapshot.gatearray.palette[3]=0x1C; + ae->snapshot.gatearray.palette[4]=0x18; + ae->snapshot.gatearray.palette[5]=0x1D; + ae->snapshot.gatearray.palette[6]=0x0C; + ae->snapshot.gatearray.palette[7]=0x05; + ae->snapshot.gatearray.palette[8]=0x0D; + ae->snapshot.gatearray.palette[9]=0x16; + ae->snapshot.gatearray.palette[10]=0x06; + ae->snapshot.gatearray.palette[11]=0x17; + ae->snapshot.gatearray.palette[12]=0x1E; + ae->snapshot.gatearray.palette[13]=0x00; + ae->snapshot.gatearray.palette[14]=0x1F; + ae->snapshot.gatearray.palette[15]=0x0E; + ae->snapshot.gatearray.palette[16]=0x04; + + ae->snapshot.gatearray.multiconfiguration=0x8D; // lower/upper ROM off + mode 1 + ae->snapshot.CPCType=2; /* 6128 */ + ae->snapshot.crtcstate.model=0; /* CRTC 0 */ + ae->snapshot.vsyncdelay=2; + strcpy((char *)ae->snapshot.unused6+3+0x20+8,RASM_VERSION); + /* CRTC default registers */ + ae->snapshot.crtc.registervalue[0]=0x3F; + ae->snapshot.crtc.registervalue[1]=40; + ae->snapshot.crtc.registervalue[2]=46; + ae->snapshot.crtc.registervalue[3]=0x8E; + ae->snapshot.crtc.registervalue[4]=38; + ae->snapshot.crtc.registervalue[6]=25; + ae->snapshot.crtc.registervalue[7]=30; + ae->snapshot.crtc.registervalue[9]=7; + ae->snapshot.crtc.registervalue[12]=0x30; + ae->snapshot.psg.registervalue[7]=0x3F; /* audio mix all channels OFF */ + /* PPI Init */ + ae->snapshot.ppi.control=0x82; + /* standard stack */ + ae->snapshot.registers.HSP=0xC0; + + /* + winape sprintf(symbol_line,"%s #%4X\n",ae->label[i].name,ae->label[i].ptr); + pasmo sprintf(symbol_line,"%s EQU 0%4XH\n",ae->label[i].name,ae->label[i].ptr); + rasm sprintf(symbol_line,"%s #%X B%d\n",ae->wl[ae->label[i].iw].w,ae->label[i].ptr,ae->label[i].ibank>31?0:ae->label[i].ibank); + */ +#if TRACE_PREPRO +printf("paramz\n"); +#endif + if (param && param->labelfilename) { + for (j=0;param->labelfilename[j] && param->labelfilename[j][0];j++) { + rasm_printf(ae,"Label import from [%s]\n",param->labelfilename[j]); + ae->label_filename=param->labelfilename[j]; + ae->label_line=1; + labelines=FileReadLines(param->labelfilename[j]); + i=0; + while (labelines[i]) { + /* upper case */ + for (j=0;labelines[i][j];j++) labelines[i][j]=toupper(labelines[i][j]); + + if ((labelsep1=strstr(labelines[i],": EQU 0"))!=NULL) { + /* sjasm */ + *labelsep1=0; + curlabel.name=labelines[i]; + curlabel.iw=-1; + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=strtol(labelsep1+6,NULL,16); + PushLabelLight(ae,&curlabel); + } else if ((labelsep1=strstr(labelines[i]," EQU 0"))!=NULL) { + /* pasmo */ + *labelsep1=0; + curlabel.name=labelines[i]; + curlabel.iw=-1; + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=strtol(labelsep1+6,NULL,16); + //ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); + PushLabelLight(ae,&curlabel); + } else if ((labelsep1=strstr(labelines[i]," "))!=NULL) { + /* winape / rasm */ + if (*(labelsep1+1)=='#') { + *labelsep1=0; + curlabel.name=labelines[i]; + curlabel.iw=-1; + curlabel.crc=GetCRC(curlabel.name); + curlabel.ptr=strtol(labelsep1+2,NULL,16); + //ObjectArrayAddDynamicValueConcat((void **)&ae->label,&ae->il,&ae->ml,&curlabel,sizeof(curlabel)); + PushLabelLight(ae,&curlabel); + } + } + i++; + ae->label_line++; + } + MemFree(labelines); + } + ae->label_filename=NULL; + ae->label_line=0; + } +#if TRACE_PREPRO +printf("init 3\n"); +#endif + /* 32 CPR default roms but 260+ max snapshot RAM pages + one workspace */ + for (i=0;i<BANK_MAX_NUMBER+1;i++) { + mem=MemMalloc(65536); + memset(mem,0,65536); + ObjectArrayAddDynamicValueConcat((void**)&ae->mem,&ae->nbbank,&ae->maxbank,&mem,sizeof(mem)); + } +#if TRACE_PREPRO +printf("nbbank=%d initialised\n",ae->nbbank); +#endif + ae->activebank=BANK_MAX_NUMBER; + ae->maxptr=65536; + for (i=0;i<256;i++) { ae->charset[i]=(unsigned char)i; } + + if (param && param->outputfilename) { + ae->outputfilename=TxtStrDup(param->outputfilename); + } else if (param && param->automatic_radix && param->filename) { + int rilook; + rilook=strlen(param->filename); + ae->outputfilename=TxtStrDup(param->filename); + /* look for extension */ + while (rilook && ae->outputfilename[rilook]!='.') { + /* end of scan with directory reference or nothing found */ + if (ae->outputfilename[rilook]=='/' || ae->outputfilename[rilook]=='\\') rilook=0; else rilook--; + } + if (ae->outputfilename[rilook]=='.') { + ae->outputfilename[rilook]=0; + } + } else { + ae->outputfilename=TxtStrDup("rasmoutput"); + } + /* si on est en ligne de commande ET que le fichier n'est pas trouvé */ + if (param && param->filename && !FileExists(param->filename)) { + char *LTryExtension[]={".asm",".z80",".o",".dam",".mxm",".txt", + ".ASM",".Z80",".O",".DAM",".MXM",".TXT",NULL}; + + int iguess=1; + l=strlen(param->filename); + filename=MemRealloc(param->filename,l+6); + /* si le nom du fichier termine par un . on n'ajoute que l'extension, sinon on l'ajoute avec le . */ + if (param->filename[l-1]=='.') strcat(param->filename,"asm"); else strcat(param->filename,".asm"); + + while (!FileExists(param->filename) && LTryExtension[iguess]!=NULL) { + TxtReplace(param->filename,LTryExtension[iguess-1],LTryExtension[iguess],0); /* no realloc with this */ + if (!FileExists(param->filename)) { + param->filename[l]=0; + } + iguess++; + } + } + + if (param && param->filename && !FileExists(param->filename)) { + rasm_printf(ae,"Cannot find file [%s]\n",param->filename); + exit(-1802); + } + + if (param) rasm_printf(ae,KAYGREEN"Pre-processing [%s]\n",param->filename); + for (nbinstruction=0;instruction[nbinstruction].mnemo[0];nbinstruction++); + qsort(instruction,nbinstruction,sizeof(struct s_asm_keyword),cmpkeyword); + for (i=0;i<256;i++) { ae->fastmatch[i]=-1; } + for (i=0;i<nbinstruction;i++) { if (ae->fastmatch[(int)instruction[i].mnemo[0]]==-1) ae->fastmatch[(int)instruction[i].mnemo[0]]=i; } + for (i=0;CharWord[i];i++) {Automate[((int)CharWord[i])&0xFF]=1;} + /* separators */ + Automate[' ']=2; + Automate[',']=2; + Automate['\t']=2; + /* end of line */ + Automate[':']=3; /* les 0x0A et 0x0D seront deja remplaces en ':' */ + /* expression */ + Automate['=']=4; /* on stocke l'emplacement de l'egalite */ + Automate['<']=4; /* ou des operateurs */ + Automate['>']=4; /* d'evaluation */ + Automate['!']=4; + + StateMachineResizeBuffer(&w,256,&mw); + StateMachineResizeBuffer(&bval,256,&sval); + StateMachineResizeBuffer(&qval,256,&sqval); + w[0]=0; + bval[0]=0; + qval[0]=0; + +#if TRACE_PREPRO +printf("read file/flux\n"); +#endif +#if TRACE_GENERALE +printf("-read/flux\n"); +#endif + + if (!ae->flux) { + zelines=FileReadLines(filename); + FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,filename); + } else { + int flux_nblines=0; + int flux_curpos; + + /* copie des données */ + for (i=0;i<datalen;i++) { + if (datain[i]=='\n') flux_nblines++; + } + zelines=MemMalloc(sizeof(char *)*(flux_nblines+2)); + flux_nblines=0; + flux_curpos=0; + for (i=0;i<datalen;i++) { + if (datain[i]=='\n') { + /* almost empty lines must allocate CR+terminator */ + zelines[flux_nblines]=MemMalloc(i-flux_curpos+2); + /* copy data+CR */ + memcpy(zelines[flux_nblines],datain+flux_curpos,i-flux_curpos+1); + /* et on ajoute un petit zéro à la fin! */ + zelines[flux_nblines][i-flux_curpos+1]=0; +#if 0 +if (flux_nblines<50) printf("%02d[%s]\n",flux_nblines,zelines[flux_nblines]); +#endif + flux_curpos=i+1; + flux_nblines++; + } + } + if (i>flux_curpos) { + zelines[flux_nblines]=MemMalloc(i-flux_curpos+1); + memcpy(zelines[flux_nblines],datain+flux_curpos,i-flux_curpos); + zelines[flux_nblines][i-flux_curpos]=0; + flux_nblines++; + } + /* terminator */ + zelines[flux_nblines]=NULL; + + /* en mode flux on prend le repertoire courant en reference */ + FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,CURRENT_DIR); + } + +#if TRACE_PREPRO +printf("remove comz, do includes\n"); +#endif +#if TRACE_GENERALE +printf("-comz/include\n"); +#endif + EarlyPrepSrc(ae,zelines,ae->filename[ae->ifile-1]); + + for (i=0;zelines[i];i++) { + curlisting.ifile=0; + curlisting.iline=i+1; + curlisting.listing=zelines[i]; + ObjectArrayAddDynamicValueConcat((void**)&listing,&ilisting,&maxlisting,&curlisting,sizeof(curlisting)); + } + MemFree(zelines); + + /* on s'assure que la derniere instruction est prise en compte a peu de frais */ + if (ilisting) { + datalen=strlen(listing[ilisting-1].listing); + listing[ilisting-1].listing=MemRealloc(listing[ilisting-1].listing,datalen+2); + listing[ilisting-1].listing[datalen]=':'; + listing[ilisting-1].listing[datalen+1]=0; + } + + waiting_quote=quote_type=0; + l=idx=0; + while (l<ilisting) { + c=listing[l].listing[idx++]; + if (!c) { + l++; + idx=0; + continue; + } else if (c=='\\' && !waiting_quote) { + idx++; + continue; + } else if (c==0x0D || c==0x0A) { + listing[l].listing[idx-1]=':'; + c=':'; + } else if (c=='\'' && idx>2 && strncmp(&listing[l].listing[idx-3],"AF'",3)==0) { + /* rien */ + } else if (c=='"' || c=='\'') { + if (!quote_type) { + quote_type=c; + lquote=l; + } else { + if (c==quote_type) { + quote_type=0; + } + } + } + + if (waiting_quote) { + /* expecting quote and nothing else */ + switch (waiting_quote) { + case 1: + if (c==quote_type) waiting_quote=2; + break; + case 2: + if (!quote_type) { + waiting_quote=3; + qval[iqval]=0; + } else { + qval[iqval++]=c; + StateMachineResizeBuffer(&qval,iqval,&sqval); + qval[iqval]=0; + } + } + if (waiting_quote==3) { + if (incbin) { + int fileok=0,ilookfile; + /* qval contient le nom du fichier a lire */ + filename_toread=MergePath(ae,ae->filename[listing[l].ifile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } else { + for (ilookfile=0;ilookfile<ae->ipath && !fileok;ilookfile++) { + filename_toread=MergePath(ae,ae->includepath[ilookfile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } + } + } + + curhexbin.filename=TxtStrDup(filename_toread); + curhexbin.crunch=crunch; + if (fileok) { + /* lecture */ + curhexbin.rawlen=curhexbin.datalen=FileGetSize(filename_toread); + curhexbin.data=MemMalloc(curhexbin.datalen*1.3+10); + #if TRACE_PREPRO + switch (crunch) { + case 0:rasm_printf(ae,KBLUE"incbin [%s] size=%d\n",filename_toread,curhexbin.datalen);break; + case 4:rasm_printf(ae,KBLUE"inclz4 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; + case 7:rasm_printf(ae,KBLUE"incsx7 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; + case 8:rasm_printf(ae,KBLUE"incexo [%s] size=%d\n",filename_toread,curhexbin.datalen);break; + case 88:rasm_printf(ae,KBLUE"incexb [%s] size=%d\n",filename_toread,curhexbin.datalen);break; + case 48:rasm_printf(ae,KBLUE"incl48 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; + case 49:rasm_printf(ae,KBLUE"incl49 [%s] size=%d\n",filename_toread,curhexbin.datalen);break; + default:rasm_printf(ae,KBLUE"invalid crunch state!\n");exit(-42); + } + #endif + if (FileReadBinary(filename_toread,(char*)curhexbin.data,curhexbin.datalen)!=curhexbin.datalen) { + rasm_printf(ae,"read error on %s",filename_toread); + exit(2); + } + FileReadBinaryClose(filename_toread); + switch (crunch) { + #ifndef NO_3RD_PARTIES + case 4: + newdata=LZ4_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); + MemFree(curhexbin.data); + curhexbin.data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ4 into %d byte(s)\n",curhexbin.datalen); + #endif + break; + case 7: + { + size_t slzlen; + newdata=ZX7_compress(optimize(curhexbin.data, curhexbin.datalen), curhexbin.data, curhexbin.datalen, &slzlen); + curhexbin.datalen=slzlen; + MemFree(curhexbin.data); + curhexbin.data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with ZX7 into %d byte(s)\n",curhexbin.datalen); + #endif + } + break; + case 8: + rasm_printf(ae,KWARNING"Exomizer is crunching %.1fkb this may take a while, be patient...\n",curhexbin.datalen/1024.0); + newdata=Exomizer_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); + MemFree(curhexbin.data); + curhexbin.data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with Exomizer into %d byte(s)\n",curhexbin.datalen); + #endif + break; + #endif + case 48: + newdata=LZ48_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); + MemFree(curhexbin.data); + curhexbin.data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched with LZ48 into %d byte(s)\n",curhexbin.datalen); + #endif + break; + case 49: + newdata=LZ49_crunch(curhexbin.data,curhexbin.datalen,&curhexbin.datalen); + MemFree(curhexbin.data); + curhexbin.data=newdata; + #if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"crunched into with LZ49 %d byte(s)\n",curhexbin.datalen); + #endif + break; + default:break; + } + } else { + /* TAG + info */ + curhexbin.datalen=-1; + curhexbin.data=MemMalloc(2); + /* not yet an error, we will know later when executing the code */ + } + ObjectArrayAddDynamicValueConcat((void**)&ae->hexbin,&ae->ih,&ae->mh,&curhexbin,sizeof(curhexbin)); + /* insertion */ + le=strlen(listing[l].listing); + + newlistingline=MemMalloc(le+32); + memcpy(newlistingline,listing[l].listing,rewrite); + rewrite+=sprintf(newlistingline+rewrite,"HEXBIN #%X",ae->ih-1); + strcat(newlistingline+rewrite,listing[l].listing+idx); + idx=rewrite; + MemFree(listing[l].listing); + listing[l].listing=newlistingline; + incbin=0; + } else if (include) { + /* qval contient le nom du fichier a lire */ + int fileok=0,ilookfile; + /* qval contient le nom du fichier a lire */ + filename_toread=MergePath(ae,ae->filename[listing[l].ifile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } else { + for (ilookfile=0;ilookfile<ae->ipath && !fileok;ilookfile++) { + filename_toread=MergePath(ae,ae->includepath[ilookfile],qval); + if (FileExists(filename_toread)) { + fileok=1; + } + } + } + + if (fileok) { + int newi,newj; + #if TRACE_PREPRO + rasm_printf(ae,KBLUE"include [%s]\n",filename_toread); + #endif + + /* lecture */ + listing_include=FileReadLines(filename_toread); + FieldArrayAddDynamicValueConcat(&ae->filename,&ae->ifile,&ae->maxfile,filename_toread); + /* virer les commentaires + pré-traitement */ + EarlyPrepSrc(ae,listing_include,ae->filename[ae->ifile-1]); + + /* split de la ligne en cours + suppression de l'instruction include */ + PreProcessingSplitListing(&listing,&ilisting,&maxlisting,l,rewrite,idx); + /* insertion des nouvelles lignes + reference fichier + numeros de ligne */ + PreProcessingInsertListing(&listing,&ilisting,&maxlisting,l,listing_include,ae->ifile-1); + + MemFree(listing_include); /* free le tableau mais pas les lignes */ + listing_include=NULL; + idx=0; /* on reste sur la meme ligne mais on se prepare a relire du caractere 0! */ + } else { + /* TAG + info */ + curhexbin.filename=TxtStrDup(filename_toread); + curhexbin.datalen=-2; + curhexbin.data=MemMalloc(2); + /* not yet an error, we will know later when executing the code */ + ObjectArrayAddDynamicValueConcat((void**)&ae->hexbin,&ae->ih,&ae->mh,&curhexbin,sizeof(curhexbin)); + /* insertion */ + le=strlen(listing[l].listing); + newlistingline=MemMalloc(le+32); + memcpy(newlistingline,listing[l].listing,rewrite); + rewrite+=sprintf(newlistingline+rewrite,"HEXBIN #%X",ae->ih-1); + strcat(newlistingline+rewrite,listing[l].listing+idx); + idx=rewrite; + MemFree(listing[l].listing); + listing[l].listing=newlistingline; + } + include=0; + } + waiting_quote=0; + qval[0]=0; + iqval=0; + } + } else { + /* classic behaviour */ + + /* looking for include/incbin */ + if (((c>='A' && c<='Z') || (c>='0' && c<='9') || c=='@' || c=='_')&& !quote_type) { + bval[ival++]=c; + StateMachineResizeBuffer(&bval,ival,&sval); + bval[ival]=0; + } else { + if (strcmp(bval,"INCLUDE")==0) { + include=1; + waiting_quote=1; + rewrite=idx-7-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"READ")==0) { + include=1; + waiting_quote=1; + rewrite=idx-4-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCLZ4")==0) { + incbin=1; + crunch=4; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCEXB")==0) { + incbin=1; + crunch=88; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCEXO")==0) { + incbin=1; + crunch=8; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCZX7")==0) { + incbin=1; + crunch=7; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCL48")==0) { + incbin=1; + crunch=48; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCL49")==0) { + incbin=1; + crunch=49; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCBIN")==0) { + incbin=1; + crunch=0; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"INCWAV")==0) { + incbin=1; + crunch=0; + waiting_quote=1; + rewrite=idx-6-1; + /* quote right after keyword */ + if (c==quote_type) { + waiting_quote=2; + } + } else if (strcmp(bval,"WHILE")==0) { + /* remplir la structure repeat_index */ + windex.ol=listing[l].iline; + windex.oidx=idx; + windex.ifile=ae->ifile-1; + ObjectArrayAddDynamicValueConcat((void**)&TABwindex,&nwi,&mwi,&windex,sizeof(windex)); + } else if (strcmp(bval,"REPEAT")==0) { + /* remplir la structure repeat_index */ + rindex.ol=listing[l].iline; + rindex.oidx=idx; + rindex.ifile=ae->ifile-1; + ObjectArrayAddDynamicValueConcat((void**)&TABrindex,&nri,&mri,&rindex,sizeof(rindex)); + } else if (strcmp(bval,"WEND")==0) { + /* retrouver la structure repeat_index correspondant a l'ouverture */ + for (wi=nwi-1;wi>=0;wi--) { + if (TABwindex[wi].cl==-1) { + TABwindex[wi].cl=c; + TABwindex[wi].cidx=idx; + break; + } + } + if (wi==-1) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"WEND refers to unknown WHILE\n"); + //exit(1); + } + } else if (strcmp(bval,"REND")==0 || strcmp(bval,"UNTIL")==0) { + /* retrouver la structure repeat_index correspondant a l'ouverture */ + for (ri=nri-1;ri>=0;ri--) { + if (TABrindex[ri].cl==-1) { + TABrindex[ri].cl=c; + TABrindex[ri].cidx=idx; + break; + } + } + if (ri==-1) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"%s refers to unknown REPEAT\n",bval); + //exit(1); + } + + } + bval[0]=0; + ival=0; + } + } + } +#if TRACE_PREPRO +printf("check quotes and repeats\n"); +#endif + if (quote_type) { + MakeError(ae,ae->filename[listing[lquote].ifile],listing[lquote].iline,"quote opened was not closed\n"); + //exit(1); + } + + /* repeat expansion check */ + for (ri=0;ri<nri;ri++) { + if (TABrindex[ri].cl==-1) { + MakeError(ae,ae->filename[TABrindex[ri].ifile],TABrindex[ri].ol,"REPEAT was not closed\n"); + } + } + + /* creer une liste de mots */ + curw.w=TxtStrDup("BEGIN"); + curw.l=0; + curw.ifile=0; + curw.t=1; + curw.e=0; + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + + /* pour les calculs d'adresses avec IX et IY on enregistre deux variables bidons du meme nom */ + curw.e=2; + curw.w=TxtStrDup("IX~0"); + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.w=TxtStrDup("IY~0"); + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.e=0; + +#if TRACE_PREPRO + l=0; + while (l<ilisting) { + rasm_printf(ae,"listing[%d]\n%s\n",l,listing[l].listing); + l++; + } +#endif +#if TRACE_GENERALE +printf("-build wordlist\n"); +#endif + + texpr=quote_type=0; + l=lw=idx=0; + ispace=0; + w[0]=0; + while (l<ilisting) { + c=listing[l].listing[idx++]; + if (!c) { + idx=0; + l++; + continue; + } + + if (!quote_type) { +#if TRACE_PREPRO +//printf("c='%c' automate[c]=%d\n",c>31?c:'.',Automate[((int)c)&0xFF]); +#endif + switch (Automate[((int)c)&0xFF]) { + case 0: + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"invalid char '%c' (%d) char %d\n",c,c,idx); +#if TRACE_PREPRO +printf("c='%c' automate[c]=%d\n",c>31?c:'.',Automate[((int)c)&0xFF]); +#endif + exit(0); + break; + case 1: + if (c=='\'' && idx>2 && strncmp(&listing[l].listing[idx-3],"AF'",3)==0) { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + break; + } else if (c=='\'' || c=='"') { + quote_type=c; + /* debut d'une quote, on finalise le mot -> POURQUOI DONC? */ + //idx--; +#if TRACE_PREPRO +printf("quote\n"); +#endif + /* on finalise le mot si on est en début d'une nouvelle instruction ET que c'est un SAVE */ + if (strcmp(w,"SAVE")==0) { + idx--; + } else { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + break; + } + } else { + if (c!=' ' && c!='\t') { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } else { + /* Winape/Maxam operator compatibility on expressions */ +#if TRACE_PREPRO +printf("1/2 winape maxam operator test for [%s]\n",w+ispace); +#endif + if (texpr) { + if (strcmp(w+ispace,"AND")==0) { + w[ispace]='&'; + lw=ispace+1; + } else if (strcmp(w+ispace,"OR")==0) { +#if TRACE_PREPRO +printf("conversion OR vers |\n"); +#endif + w[ispace]='|'; + lw=ispace+1; + } else if (strcmp(w+ispace,"MOD")==0) { + w[ispace]='m'; + lw=ispace+1; + } else if (strcmp(w+ispace,"XOR")==0) { + w[ispace]='^'; + lw=ispace+1; + } else if (strcmp(w+ispace,"%")==0) { + w[ispace]='m'; + lw=ispace+1; + } + } + ispace=lw; + } + break; + } + case 2: + /* separator (space, tab, comma) */ +#if TRACE_PREPRO +printf("*** separator='%c'\n",c); +#endif + + /* patch argument suit une expression d'évaluation (ASSERT) */ + if (c==',') hadcomma=1; + + if (lw) { + w[lw]=0; + if (texpr && !wordlist[nbword-1].t && wordlist[nbword-1].e && !hadcomma) { + /* pour compatibilite winape avec AND,OR,XOR */ +#if TRACE_PREPRO +printf("2/2 winape maxam operator test for expression [%s]\n",w+ispace); +#endif + if (strcmp(w,"AND")==0) { + wtmp=TxtStrDup("&"); + } else if (strcmp(w,"OR")==0) { + wtmp=TxtStrDup("|"); + } else if (strcmp(w,"XOR")==0) { + wtmp=TxtStrDup("^"); + } else if (strcmp(w,"%")==0) { + wtmp=TxtStrDup("m"); + } else { + wtmp=TxtStrDup(w); + } + /* on concatène le nouveau mot à l'expression */ + nbword--; + lw=0; + for (li=0;wordlist[nbword].w[li];li++) { + w[lw++]=wordlist[nbword].w[li]; + StateMachineResizeBuffer(&w,lw,&mw); + } + w[lw]=0; + MemFree(wordlist[nbword].w); + + for (li=0;wtmp[li];li++) { + w[lw++]=wtmp[li]; + StateMachineResizeBuffer(&w,lw,&mw); + } + w[lw]=0; + MemFree(wtmp); + /* et on modifie l'automate pour la suite! */ + Automate[' ']=1; + Automate['\t']=1; + ispace=lw; + } else if (strcmp(w,"EQU")==0) { + /* il y avait un mot avant alors on va reorganiser la ligne */ + nbword--; + lw=0; + for (li=0;wordlist[nbword].w[li];li++) { + w[lw++]=wordlist[nbword].w[li]; + StateMachineResizeBuffer(&w,lw,&mw); + } + MemFree(wordlist[nbword].w); + curw.e=lw+1; + /* on ajoute l'egalite d'alias*/ + w[lw++]='~'; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + Automate[' ']=1; + Automate['\t']=1; + ispace=lw; + texpr=1; + } else { + curw.w=TxtStrDup(w); + curw.l=listing[l].iline; + curw.ifile=listing[l].ifile; + curw.t=0; +#if TRACE_PREPRO +if (curw.w[0]=='=') { + printf("(1) bug prout\n"); + exit(1); +} +printf("ajout du mot [%s]\n",curw.w); +#endif + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + //texpr=0; /* reset expr */ + curw.e=0; + lw=0; + w[lw]=0; + + /* match keyword? then next spaces will be ignored*/ + if (macro_trigger) { + struct s_macro_fast curmacrofast; + Automate[' ']=1; + Automate['\t']=1; + ispace=0; + texpr=1; +#if TRACE_PREPRO +printf("macro trigger w=[%s]\n",curw.w); +#endif + /* add macro name to instruction pool for preprocessor but not struct or write */ + if (macro_trigger=='M') { + curmacrofast.mnemo=curw.w; + curmacrofast.crc=GetCRC(curw.w); + ObjectArrayAddDynamicValueConcat((void**)&MacroFast,&idxmacrofast,&maxmacrofast,&curmacrofast,sizeof(struct s_macro_fast)); + } + macro_trigger=0; + } else { + int keymatched=0; + if ((ifast=ae->fastmatch[(int)curw.w[0]])!=-1) { + while (instruction[ifast].mnemo[0]==curw.w[0]) { + if (strcmp(instruction[ifast].mnemo,curw.w)==0) { + keymatched=1; + if (strcmp(curw.w,"MACRO")==0 || strcmp(curw.w,"STRUCT")==0 || strcmp(curw.w,"WRITE")==0) { +/* @@TODO AS80 compatibility patch!!! */ + macro_trigger=curw.w[0]; + } else { + Automate[' ']=1; + Automate['\t']=1; + ispace=0; + /* instruction en cours, le reste est a interpreter comme une expression */ +#if TRACE_PREPRO +printf("instruction en cours\n"); +#endif + texpr=1; + } + break; + } + ifast++; + } + } + if (!keymatched) { + int macrocrc; + macrocrc=GetCRC(curw.w); + for (keymatched=0;keymatched<idxmacrofast;keymatched++) { + if (MacroFast[keymatched].crc==macrocrc) + if (strcmp(MacroFast[keymatched].mnemo,curw.w)==0) { + Automate[' ']=1; + Automate['\t']=1; + ispace=0; + /* macro en cours, le reste est a interpreter comme une expression */ + texpr=1; + break; + } + } + } + } + } + } else { + if (hadcomma) { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"empty parameter\n"); + } + } + break; + case 3: + /* fin de ligne, on remet l'automate comme il faut */ +#if TRACE_PREPRO +printf("EOL\n"); +#endif + macro_trigger=0; + Automate[' ']=2; + Automate['\t']=2; + ispace=0; + texpr=0; + /* si le mot lu a plus d'un caractère */ + if (lw) { + if (!wordlist[nbword-1].t && (wordlist[nbword-1].e || w[0]=='=') && !hadcomma) { + /* cas particulier d'ecriture libre */ + /* bugfix inhibition 19.06.2018 */ + /* ajout du terminateur? */ + w[lw]=0; +#if TRACE_PREPRO +printf("nbword=%d w=[%s] ->",nbword,w);fflush(stdout); +#endif + nbword--; + wordlist[nbword].w=MemRealloc(wordlist[nbword].w,strlen(wordlist[nbword].w)+lw+1); + strcat(wordlist[nbword].w,w); +#if TRACE_PREPRO +printf("%s\n",wordlist[nbword].w); +#endif + /* on change de type! */ + wordlist[nbword].t=1; + //ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.e=0; + lw=0; + w[lw]=0; + } else if (nbword && strcmp(w,"EQU")==0) { + /* il y avait un mot avant alors on va reorganiser la ligne */ + nbword--; + lw=0; + for (li=0;wordlist[nbword].w[li];li++) { + w[lw++]=wordlist[nbword].w[li]; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } + MemFree(wordlist[nbword].w); + /* on ajoute l'egalite ou comparaison! */ + curw.e=lw+1; + w[lw++]='='; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + Automate[' ']=1; + Automate['\t']=1; + } else { + /* mot de fin de ligne, à priori pas une expression */ + curw.w=TxtStrDup(w); + curw.l=listing[l].iline; + curw.ifile=listing[l].ifile; + curw.t=1; +#if TRACE_PREPRO +printf("mot de fin de ligne = [%s]\n",curw.w); +if (curw.w[0]=='=') { + printf("(3) bug prout\n"); + exit(1); +} +#endif + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); + curw.e=0; + lw=0; + w[lw]=0; + hadcomma=0; + } + } else { + /* sinon c'est le précédent qui était terminateur d'instruction */ + wordlist[nbword-1].t=1; + w[lw]=0; + } + hadcomma=0; + break; + case 4: +#if TRACE_PREPRO +printf("expr operator=%c\n",c); +#endif + /* expression/condition */ + texpr=1; + if (lw) { + Automate[' ']=1; + Automate['\t']=1; + if (!curw.e) { + curw.e=lw+1; + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } else { + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } + } else { + /* 2018.06.06 évolution sur le ! (not) */ +#if TRACE_PREPRO +printf("*** operateur commence le mot\n"); +printf("mot precedent=[%s] t=%d\n",wordlist[nbword-1].w,wordlist[nbword-1].t); +#endif + if (hadcomma && c=='!') { + /* on peut commencer un argument par un NOT */ + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + /* automate déjà modifié rien de plus */ + } else if (!wordlist[nbword-1].t) { + /* il y avait un mot avant alors on va reorganiser la ligne */ + /* patch NOT -> SAUF si c'est une directive */ + int keymatched=0; + if ((ifast=ae->fastmatch[(int)wordlist[nbword-1].w[0]])!=-1) { + while (instruction[ifast].mnemo[0]==wordlist[nbword-1].w[0]) { + if (strcmp(instruction[ifast].mnemo,wordlist[nbword-1].w)==0) { + keymatched=1; + break; + } + ifast++; + } + } + if (!keymatched) { + int macrocrc; + macrocrc=GetCRC(wordlist[nbword-1].w); + for (i=0;i<idxmacrofast;i++) { + if (MacroFast[i].crc==macrocrc) + if (strcmp(MacroFast[i].mnemo,wordlist[nbword-1].w)==0) { + keymatched=1; + break; + } + } + } + if (!keymatched) { + nbword--; + for (li=0;wordlist[nbword].w[li];li++) { + w[lw++]=wordlist[nbword].w[li]; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + } + MemFree(wordlist[nbword].w); + /* on ajoute l'egalite ou comparaison! */ + curw.e=lw+1; + } + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + /* et on modifie l'automate pour la suite! */ + Automate[' ']=1; + Automate['\t']=1; + } else { + MakeError(ae,ae->filename[listing[l].ifile],listing[l].iline,"cannot start expression with '=','!','<','>'\n"); + } + } + break; + default: + rasm_printf(ae,KERROR"Internal error (Automate wrong value=%d)\n",Automate[c]); + exit(-1); + } + } else { + /* lecture inconditionnelle de la quote */ +#if TRACE_PREPRO +printf("quote[%d]=%c\n",lw,c); +#endif + w[lw++]=c; + StateMachineResizeBuffer(&w,lw,&mw); + w[lw]=0; + if (!escape_code) { + if (c=='\\') escape_code=1; + if (lw>1 && c==quote_type) { + quote_type=0; + } + } else { + escape_code=0; + } + } + } + +#if TRACE_PREPRO +printf("END\n"); +#endif + + curw.w="END"; + curw.l=0; + curw.t=2; + curw.ifile=0; + ObjectArrayAddDynamicValueConcat((void**)&wordlist,&nbword,&maxword,&curw,sizeof(curw)); +#if TRACE_PREPRO + rasm_printf(ae,KVERBOSE"wordlist contains %d element%s\n",nbword,nbword>1?"s":""); +#endif + ae->nbword=nbword; + + /* switch words for macro declaration with AS80 & UZ80 */ + if (param && param->as80) { + for (l=0;l<nbword;l++) { + if (!wordlist[l].t && !wordlist[l].e && strcmp(wordlist[l+1].w,"MACRO")==0) { + char *wtmp; + wtmp=wordlist[l+1].w; + wordlist[l+1].w=wordlist[l].w; + wordlist[l].w=wtmp; + } + } + } + +#if TRACE_PREPRO + for (l=0;l<nbword;l++) { + rasm_printf(ae,"[%s]e=%d ",wordlist[l].w,wordlist[l].e); + if (wordlist[l].t) rasm_printf(ae,"(%d)\n",wordlist[l].t); + } + +printf("free\n"); +#endif + + MemFree(bval); + MemFree(qval); + MemFree(w); + + for (l=0;l<ilisting;l++) { + MemFree(listing[l].listing); + } + MemFree(listing); + /* wordlist + type 0: label or instruction followed by parameter(s) + type 1: last word of the line, last parameter of an instruction + type 2: very last word of the list + e tag: non zero if there is comparison or equality + */ + ae->wl=wordlist; + if (param) { + MemFree(param->filename); + } + if (MacroFast) MemFree(MacroFast); + if (TABwindex) MemFree(TABwindex); + if (TABrindex) MemFree(TABrindex); +#if TRACE_PREPRO +printf("return ae\n"); +#endif + return ae; +} + +int Rasm(struct s_parameter *param) +{ + #undef FUNC + #define FUNC "Rasm" + + struct s_assenv *ae=NULL; + + /* read and preprocess source */ + ae=PreProcessing(param->filename,0,NULL,0,param); + /* assemble */ + return Assemble(ae,NULL,NULL,NULL); +} + +/* fonction d'export */ + +int RasmAssemble(const char *datain, int lenin, unsigned char **dataout, int *lenout) +{ + struct s_assenv *ae=NULL; + + if (lenout) *lenout=0; + ae=PreProcessing(NULL,1,datain,lenin,NULL); + return Assemble(ae,dataout,lenout,NULL); +} + +int RasmAssembleInfo(const char *datain, int lenin, unsigned char **dataout, int *lenout, struct s_rasm_info **debug) +{ + struct s_assenv *ae=NULL; + int ret; + + ae=PreProcessing(NULL,1,datain,lenin,NULL); + ret=Assemble(ae,dataout,lenout,debug); + return ret; +} + + +#define AUTOTEST_PAGELABELGEN "buildsna: bank: cpt=5: ld bc,{page}miam{cpt}: bank cpt: nop: miam{cpt} nop: assert {page}miam{cpt}==0x7FC5 " + +#define AUTOTEST_NOINCLUDE "truc equ 0:if truc:include'bite':endif:nop" + +#define AUTOTEST_SETINSIDE "ld hl,0=0xC9FB" + +#define AUTOTEST_OPERATOR_CONVERSION "ld hl,10 OR 20:ld a,40 and 10:ld bc,5 MOD 2:ld a,(ix+45 xor 45)" + +#define AUTOTEST_OPERATOR_MODULO "revar=46: devar=5 : var=46%5 : assert var==1: var=46 % 5 : assert var==1: var=46 mod 5 : assert var==1:" \ + "var=revar%5 : assert var==1: var=revar%devar : assert var==1: var=46%devar : assert var==1: var=revar % 5 : assert var==1:" \ + "var=revar % devar : assert var==1: var=46 % devar : assert var==1: var=revar % %101 : assert var==1: var=revar%%101 : assert var==1: nop" + +#define AUTOTEST_UNDEF "mavar=10: ifdef mavar: undef mavar: endif: ifdef mavar: fail 'undef did not work': endif:nop " + +#define AUTOTEST_INSTRMUSTFAILED "ld a,b,c:ldi a: ldir bc:exx hl,de:exx de:ex bc,hl:ex hl,bc:ex af,af:ex hl,hl:ex hl:exx hl: "\ + "neg b:push b:push:pop:pop c:sub ix:add ix:add:sub:di 2:ei 3:ld i,c:ld r,e:rl:rr:rlca a:sla:sll:"\ + "ldd e:lddr hl:adc ix:adc b,a:xor 12,13:xor b,1:xor:or 12,13:or b,1:or:and 12,13:and b,1:and:inc:dec" + +#define AUTOTEST_VIRGULE "defb 5,5,,5" +#define AUTOTEST_VIRGULE2 "print '5,,5':nop" + +#define AUTOTEST_OVERLOADMACPRM "macro test,idx: defb idx:endm:macro test2,idx:defb {idx}:endm:repeat 2,idx:test idx-1:test2 idx-1:rend" + +#define AUTOTEST_IFDEFMACRO "macro test:nop:endm:ifndef test:error:else:test:endif:ifdef test:test:else:error:endif:nop" + +#define AUTOTEST_PRINTVAR "label1: macro test, param: print 'param {param}', {hex}{param}: endm:: test label1: nop" + +#define AUTOTEST_PRINTSPACE "idx=5: print 'grouik { idx + 3 } ':nop" + +#define AUTOTEST_NOT "myvar=10:myvar=10+myvar:if 5!=3:else:print glop:endif:ifnot 5:print glop:else:endif:" \ + "ifnot 0:else:print glop:endif:if !(5):print glop:endif:if !(0):else:print glop:endif:" \ + "ya=!0:if ya==1:else:print glop:endif:if !5:print glop:endif:ya = 0:ya =! 0:if ya == 1:" \ + "else:print glop:endif:if ! 5:print glop:endif:if 1-!( !0 && !0):else:print glop:endif:nop" + + +#define AUTOTEST_MACRO "macro glop:@glop:ld hl,@next:djnz @glop:@next:mend:macro glop2:@glop:glop:ld hl,@next:djnz @glop:glop:" \ + "@next:mend:cpti=0:repeat:glop:cpt=0:glop:repeat:glop2:repeat 1:@glop:dec a:ld hl,@next:glop2:glop2:" \ + "jr nz,@glop:@next:rend:cpt=cpt+1:glop2:until cpt<3:cpti=cpti+1:glop2:until cpti<3" + +#define AUTOTEST_MACRO_ADV "idx=10:macro mac2 param1,param2:ld hl,{param1}{idx+10}{param2}:{param1}{idx+10}{param2}:djnz {param1}{idx+10}{param2}:mend: " \ + "mac2 label,45:mac2 glop,10:djnz glop2010:jp label2045" + +#define AUTOTEST_MACROPAR "macro unemac, param1, param2:defb '{param1}':defb {param2}:mend:unemac grouik,'grouik'" + +#define AUTOTEST_OPCODES "nop::ld bc,#1234::ld (bc),a::inc bc:inc b:dec b:ld b,#12:rlca:ex af,af':add hl,bc:ld a,(bc):dec bc:" \ + "inc c:dec c:ld c,#12:rrca::djnz $:ld de,#1234:ld (de),a:inc de:inc d:dec d:ld d,#12:rla:jr $:" \ + "add hl,de:ld a,(de):dec de:inc e:dec e:ld e,#12:rra::jr nz,$:ld hl,#1234:ld (#1234),hl:inc hl:inc h:" \ + "dec h:ld h,#12:daa:jr z,$:add hl,hl:ld hl,(#1234):dec hl:inc l:dec l:ld l,#12:cpl::jr nc,$:" \ + "ld sp,#1234:ld (#1234),a:inc sp:inc (hl):dec (hl):ld (hl),#12:scf:jr c,$:add hl,sp:ld a,(#1234):" \ + "dec sp:inc a:dec a:ld a,#12:ccf::ld b,b:ld b,c:ld b,d:ld b,e:ld b,h:ld b,l:ld b,(hl):ld b,a:ld c,b:" \ + "ld c,c:ld c,d:ld c,e:ld c,h:ld c,l:ld c,(hl):ld c,a::ld d,b:ld d,c:ld d,d:ld d,e:ld d,h:ld d,l:" \ + "ld d,(hl):ld d,a:ld e,b:ld e,c:ld e,d:ld e,e:ld e,h:ld e,l:ld e,(hl):ld e,a::ld h,b:ld h,c:ld h,d:" \ + "ld h,e:ld h,h:ld h,l:ld h,(hl):ld h,a:ld l,b:ld l,c:ld l,d:ld l,e:ld l,h:ld l,l:ld l,(hl):ld l,a::" \ + "ld (hl),b:ld (hl),c:ld (hl),d:ld (hl),e:ld (hl),h:ld (hl),l:halt:ld (hl),a:ld a,b:ld a,c:ld a,d:" \ + "ld a,e:ld a,h:ld a,l:ld a,(hl):ld a,a::add b:add c:add d:add e:add h:add l:add (hl):add a:adc b:" \ + "adc c:adc d:adc e:adc h:adc l:adc (hl):adc a::sub b:sub c:sub d:sub e:sub h:sub l:sub (hl):sub a:" \ + "sbc b:sbc c:sbc d:sbc e:sbc h:sbc l:sbc (hl):sbc a::and b:and c:and d:and e:and h:and l:and (hl):" \ + "and a:xor b:xor c:xor d:xor e:xor h:xor l:xor (hl):xor a::or b:or c:or d:or e:or h:or l:or (hl):" \ + "or a:cp b:cp c:cp d:cp e:cp h:cp l:cp (hl):cp a::ret nz:pop bc:jp nz,#1234:jp #1234:call nz,#1234:" \ + "push bc:add #12:rst 0:ret z:ret:jp z,#1234:nop:call z,#1234:call #1234:adc #12:rst 8::ret nc:pop de:" \ + "jp nc,#1234:out (#12),a:call nc,#1234:push de:sub #12:rst #10:ret c:exx:jp c,#1234:in a,(#12):" \ + "call c,#1234:nop:sbc #12:rst #18::ret po:pop hl:jp po,#1234:ex (sp),hl:call po,#1234:push hl:" \ + "and #12:rst #20:ret pe:jp (hl):jp pe,#1234:ex de,hl:call pe,#1234:nop:xor #12:rst #28::ret p:pop af:" \ + "jp p,#1234:di:call p,#1234:push af:or #12:rst #30:ret m:ld sp,hl:jp m,#1234:ei:call m,#1234:nop:" \ + "cp #12:rst #38:in b,(c):out (c),b:sbc hl,bc:ld (#1234),bc:neg:retn:im 0:ld i,a:in c,(c):out (c),c:" \ + "adc hl,bc:ld bc,(#1234):reti:ld r,a::in d,(c):out (c),d:sbc hl,de:ld (#1234),de:retn:im 1:ld a,i:" \ + "in e,(c):out (c),e:adc hl,de:ld de,(#1234):im 2:ld a,r::in h,(c):out (c),h:sbc hl,hl:rrd:in l,(c):" \ + "out (c),l:adc hl,hl:rld::in 0,(c):out (c),0:sbc hl,sp:ld (#1234),sp:in a,(c):out (c),a:adc hl,sp:" \ + "ld sp,(#1234)::ldi:cpi:ini:outi:ldd:cpd:ind:outd::ldir:cpir:inir:otir:lddr:cpdr:indr:otdr::rlc b:" \ + "rlc c:rlc d:rlc e:rlc h:rlc l:rlc (hl):rlc a:rrc b:rrc c:rrc d:rrc e:rrc h:rrc l:rrc (hl):rrc a::" \ + "rl b:rl c:rl d:rl e:rl h:rl l:rl (hl):rl a:rr b:rr c:rr d:rr e:rr h:rr l:rr (hl):rr a:sla b:sla c:" \ + "sla d:sla e:sla h:sla l:sla (hl):sla a:sra b:sra c:sra d:sra e:sra h:sra l:sra (hl):sra a::sll b:" \ + "sll c:sll d:sll e:sll h:sll l:sll (hl):sll a:srl b:srl c:srl d:srl e:srl h:srl l:srl (hl):srl a::" \ + "bit 0,b:bit 0,c:bit 0,d:bit 0,e:bit 0,h:bit 0,l:bit 0,(hl):bit 0,a::bit 1,b:bit 1,c:bit 1,d:bit 1,e:" \ + "bit 1,h:bit 1,l:bit 1,(hl):bit 1,a::bit 2,b:bit 2,c:bit 2,d:bit 2,e:bit 2,h:bit 2,l:bit 2,(hl):" \ + "bit 2,a::bit 3,b:bit 3,c:bit 3,d:bit 3,e:bit 3,h:bit 3,l:bit 3,(hl):bit 3,a::bit 4,b:bit 4,c:" \ + "bit 4,d:bit 4,e:bit 4,h:bit 4,l:bit 4,(hl):bit 4,a::bit 5,b:bit 5,c:bit 5,d:bit 5,e:bit 5,h:bit 5,l:" \ + "bit 5,(hl):bit 5,a::bit 6,b:bit 6,c:bit 6,d:bit 6,e:bit 6,h:bit 6,l:bit 6,(hl):bit 6,a::bit 7,b:" \ + "bit 7,c:bit 7,d:bit 7,e:bit 7,h:bit 7,l:bit 7,(hl):bit 7,a::res 0,b:res 0,c:res 0,d:res 0,e:res 0,h:" \ + "res 0,l:res 0,(hl):res 0,a::res 1,b:res 1,c:res 1,d:res 1,e:res 1,h:res 1,l:res 1,(hl):res 1,a::" \ + "res 2,b:res 2,c:res 2,d:res 2,e:res 2,h:res 2,l:res 2,(hl):res 2,a::res 3,b:res 3,c:res 3,d:res 3,e:" \ + "res 3,h:res 3,l:res 3,(hl):res 3,a::res 4,b:res 4,c:res 4,d:res 4,e:res 4,h:res 4,l:res 4,(hl):" \ + "res 4,a::res 5,b:res 5,c:res 5,d:res 5,e:res 5,h:res 5,l:res 5,(hl):res 5,a::res 6,b:res 6,c:" \ + "res 6,d:res 6,e:res 6,h:res 6,l:res 6,(hl):res 6,a::res 7,b:res 7,c:res 7,d:res 7,e:res 7,h:res 7,l:" \ + "res 7,(hl):res 7,a::set 0,b:set 0,c:set 0,d:set 0,e:set 0,h:set 0,l:set 0,(hl):set 0,a::set 1,b:" \ + "set 1,c:set 1,d:set 1,e:set 1,h:set 1,l:set 1,(hl):set 1,a::set 2,b:set 2,c:set 2,d:set 2,e:set 2,h:" \ + "set 2,l:set 2,(hl):set 2,a::set 3,b:set 3,c:set 3,d:set 3,e:set 3,h:set 3,l:set 3,(hl):set 3,a::" \ + "set 4,b:set 4,c:set 4,d:set 4,e:set 4,h:set 4,l:set 4,(hl):set 4,a::set 5,b:set 5,c:set 5,d:set 5,e:" \ + "set 5,h:set 5,l:set 5,(hl):set 5,a::set 6,b:set 6,c:set 6,d:set 6,e:set 6,h:set 6,l:set 6,(hl):" \ + "set 6,a::set 7,b:set 7,c:set 7,d:set 7,e:set 7,h:set 7,l:set 7,(hl):set 7,a::add ix,bc::add ix,de::" \ + "ld ix,#1234:ld (#1234),ix:inc ix:inc xh:dec xh:ld xh,#12:add ix,ix:ld ix,(#1234):dec ix:inc xl:" \ + "dec xl:ld xl,#12::inc (ix+#12):dec (ix+#12):ld (ix+#12),#34:add ix,sp::ld b,xh:ld b,xl:" \ + "ld b,(ix+#12):ld c,xh:ld c,xl:ld c,(ix+#12):::ld d,xh:ld d,xl:ld d,(ix+#12):ld e,xh:ld e,xl:" \ + "ld e,(ix+#12)::ld xh,b:ld xh,c:ld xh,d:ld xh,e:ld xh,xh:ld xh,xl:ld h,(ix+#12):ld xh,a:ld xl,b:" \ + "ld xl,c:ld xl,d:ld xl,e:ld xl,xh:ld xl,xl:ld l,(ix+#12):ld xl,a::ld (ix+#12),b:ld (ix+#12),c:" \ + "ld (ix+#12),d:ld (ix+#12),e:ld (ix+#12),h:ld (ix+#12),l:ld (ix+#12),a:ld a,xh:ld a,xl:" \ + "ld a,(ix+#12)::add xh:add xl:add (ix+#12):adc xh:adc xl:adc (ix+#12)::sub xh:sub xl:sub (ix+#12):" \ + "sbc xh:sbc xl:sbc (ix+#12)::and xh:and xl:and (ix+#12):xor xh:xor xl:xor (ix+#12)::or xh:or xl:" \ + "or (ix+#12):cp xh:cp xl:cp (ix+#12)::pop ix:ex (sp),ix:push ix:jp (ix)::ld sp,ix:::rlc (ix+#12),b:" \ + "rlc (ix+#12),c:rlc (ix+#12),d:rlc (ix+#12),e:rlc (ix+#12),h:rlc (ix+#12),l:rlc (ix+#12):" \ + "rlc (ix+#12),a:rrc (ix+#12),b:rrc (ix+#12),c:rrc (ix+#12),d:rrc (ix+#12),e:rrc (ix+#12),h:" \ + "rrc (ix+#12),l:rrc (ix+#12):rrc (ix+#12),a::rl (ix+#12),b:rl (ix+#12),c:rl (ix+#12),d:rl (ix+#12),e:" \ + "rl (ix+#12),h:rl (ix+#12),l:rl (ix+#12):rl (ix+#12),a:rr (ix+#12),b:rr (ix+#12),c:rr (ix+#12),d:" \ + "rr (ix+#12),e:rr (ix+#12),h:rr (ix+#12),l:rr (ix+#12):rr (ix+#12),a::sla (ix+#12),b:sla (ix+#12),c:" \ + "sla (ix+#12),d:sla (ix+#12),e:sla (ix+#12),h:sla (ix+#12),l:sla (ix+#12):sla (ix+#12),a:" \ + "sra (ix+#12),b:sra (ix+#12),c:sra (ix+#12),d:sra (ix+#12),e:sra (ix+#12),h:sra (ix+#12),l:" \ + "sra (ix+#12):sra (ix+#12),a::sll (ix+#12),b:sll (ix+#12),c:sll (ix+#12),d:sll (ix+#12),e:" \ + "sll (ix+#12),h:sll (ix+#12),l:sll (ix+#12):sll (ix+#12),a:srl (ix+#12),b:srl (ix+#12),c:" \ + "srl (ix+#12),d:srl (ix+#12),e:srl (ix+#12),h:srl (ix+#12),l:srl (ix+#12):srl (ix+#12),a::" \ + "bit 0,(ix+#12):bit 1,(ix+#12):bit 2,(ix+#12):bit 3,(ix+#12):bit 4,(ix+#12):bit 5,(ix+#12):" \ + "bit 6,(ix+#12):bit 7,(ix+#12):bit 0,(ix+#12),d:bit 1,(ix+#12),b:bit 2,(ix+#12),c:bit 3,(ix+#12),d:" \ + "bit 4,(ix+#12),e:bit 5,(ix+#12),h:bit 6,(ix+#12),l:bit 7,(ix+#12),a:::res 0,(ix+#12),b:" \ + "res 0,(ix+#12),c:res 0,(ix+#12),d:res 0,(ix+#12),e:res 0,(ix+#12),h:res 0,(ix+#12),l:res 0,(ix+#12):" \ + "res 0,(ix+#12),a::res 1,(ix+#12),b:res 1,(ix+#12),c:res 1,(ix+#12),d:res 1,(ix+#12),e:" \ + "res 1,(ix+#12),h:res 1,(ix+#12),l:res 1,(ix+#12):res 1,(ix+#12),a::res 2,(ix+#12),b:" \ + "res 2,(ix+#12),c:res 2,(ix+#12),d:res 2,(ix+#12),e:res 2,(ix+#12),h:res 2,(ix+#12),l:res 2,(ix+#12):" \ + "res 2,(ix+#12),a::res 3,(ix+#12),b:res 3,(ix+#12),c:res 3,(ix+#12),d:res 3,(ix+#12),e:" \ + "res 3,(ix+#12),h:res 3,(ix+#12),l:res 3,(ix+#12):res 3,(ix+#12),a::res 4,(ix+#12),b:" \ + "res 4,(ix+#12),c:res 4,(ix+#12),d:res 4,(ix+#12),e:res 4,(ix+#12),h:res 4,(ix+#12),l:" \ + "res 4,(ix+#12):res 4,(ix+#12),a::res 5,(ix+#12),b:res 5,(ix+#12),c:res 5,(ix+#12),d:" \ + "res 5,(ix+#12),e:res 5,(ix+#12),h:res 5,(ix+#12),l:res 5,(ix+#12):res 5,(ix+#12),a::" \ + "res 6,(ix+#12),b:res 6,(ix+#12),c:res 6,(ix+#12),d:res 6,(ix+#12),e:res 6,(ix+#12),h:" \ + "res 6,(ix+#12),l:res 6,(ix+#12):res 6,(ix+#12),a::res 7,(ix+#12),b:res 7,(ix+#12),c:" \ + "res 7,(ix+#12),d:res 7,(ix+#12),e:res 7,(ix+#12),h:res 7,(ix+#12),l:res 7,(ix+#12):" \ + "res 7,(ix+#12),a::set 0,(ix+#12),b:set 0,(ix+#12),c:set 0,(ix+#12),d:set 0,(ix+#12),e:" \ + "set 0,(ix+#12),h:set 0,(ix+#12),l:set 0,(ix+#12):set 0,(ix+#12),a::set 1,(ix+#12),b:" \ + "set 1,(ix+#12),c:set 1,(ix+#12),d:set 1,(ix+#12),e:set 1,(ix+#12),h:set 1,(ix+#12),l:" \ + "set 1,(ix+#12):set 1,(ix+#12),a::set 2,(ix+#12),b:set 2,(ix+#12),c:set 2,(ix+#12),d:" \ + "set 2,(ix+#12),e:set 2,(ix+#12),h:set 2,(ix+#12),l:set 2,(ix+#12):set 2,(ix+#12),a::" \ + "set 3,(ix+#12),b:set 3,(ix+#12),c:set 3,(ix+#12),d:set 3,(ix+#12),e:set 3,(ix+#12),h:" \ + "set 3,(ix+#12),l:set 3,(ix+#12):set 3,(ix+#12),a::set 4,(ix+#12),b:set 4,(ix+#12),c:" \ + "set 4,(ix+#12),d:set 4,(ix+#12),e:set 4,(ix+#12),h:set 4,(ix+#12),l:set 4,(ix+#12):" \ + "set 4,(ix+#12),a::set 5,(ix+#12),b:set 5,(ix+#12),c:set 5,(ix+#12),d:set 5,(ix+#12),e:" \ + "set 5,(ix+#12),h:set 5,(ix+#12),l:set 5,(ix+#12):set 5,(ix+#12),a::set 6,(ix+#12),b:" \ + "set 6,(ix+#12),c:set 6,(ix+#12),d:set 6,(ix+#12),e:set 6,(ix+#12),h:set 6,(ix+#12),l:" \ + "set 6,(ix+#12):set 6,(ix+#12),a::set 7,(ix+#12),b:set 7,(ix+#12),c:set 7,(ix+#12),d:" \ + "set 7,(ix+#12),e:set 7,(ix+#12),h:set 7,(ix+#12),l:set 7,(ix+#12):set 7,(ix+#12),a::add iy,bc::" \ + "add iy,de::ld iy,#1234:ld (#1234),iy:inc iy:inc yh:dec yh:ld yh,#12:add iy,iy:ld iy,(#1234):dec iy:" \ + "inc yl:dec yl:ld yl,#12::inc (iy+#12):dec (iy+#12):ld (iy+#12),#34:add iy,sp::ld b,yh:ld b,yl:" \ + "ld b,(iy+#12):ld c,yh:ld c,yl:ld c,(iy+#12):::ld d,yh:ld d,yl:ld d,(iy+#12):ld e,yh:ld e,yl:" \ + "ld e,(iy+#12)::ld yh,b:ld yh,c:ld yh,d:ld yh,e:ld yh,yh:ld yh,yl:ld h,(iy+#12):ld yh,a:ld yl,b:" \ + "ld yl,c:ld yl,d:ld yl,e:ld yl,yh:ld yl,yl:ld l,(iy+#12):ld yl,a::ld (iy+#12),b:ld (iy+#12),c:" \ + "ld (iy+#12),d:ld (iy+#12),e:ld (iy+#12),h:ld (iy+#12),l:ld (iy+#12),a:ld a,yh:ld a,yl:" \ + "ld a,(iy+#12)::add yh:add yl:add (iy+#12):adc yh:adc yl:adc (iy+#12)::sub yh:sub yl:" \ + "sub (iy+#12):sbc yh:sbc yl:sbc (iy+#12)::and yh:and yl:and (iy+#12):xor yh:xor yl:xor (iy+#12)::" \ + "or yh:or yl:or (iy+#12):cp yh:cp yl:cp (iy+#12)::pop iy:ex (sp),iy:push iy:jp (iy)::ld sp,iy::" \ + "rlc (iy+#12),b:rlc (iy+#12),c:rlc (iy+#12),d:rlc (iy+#12),e:rlc (iy+#12),h:rlc (iy+#12),l:" \ + "rlc (iy+#12):rlc (iy+#12),a:rrc (iy+#12),b:rrc (iy+#12),c:rrc (iy+#12),d:rrc (iy+#12),e:" \ + "rrc (iy+#12),h:rrc (iy+#12),l:rrc (iy+#12):rrc (iy+#12),a::rl (iy+#12),b:rl (iy+#12),c:" \ + "rl (iy+#12),d:rl (iy+#12),e:rl (iy+#12),h:rl (iy+#12),l:rl (iy+#12):rl (iy+#12),a:rr (iy+#12),b:" \ + "rr (iy+#12),c:rr (iy+#12),d:rr (iy+#12),e:rr (iy+#12),h:rr (iy+#12),l:rr (iy+#12):rr (iy+#12),a::" \ + "sla (iy+#12),b:sla (iy+#12),c:sla (iy+#12),d:sla (iy+#12),e:sla (iy+#12),h:sla (iy+#12),l:" \ + "sla (iy+#12):sla (iy+#12),a:sra (iy+#12),b:sra (iy+#12),c:sra (iy+#12),d:sra (iy+#12),e:" \ + "sra (iy+#12),h:sra (iy+#12),l:sra (iy+#12):sra (iy+#12),a::sll (iy+#12),b:sll (iy+#12),c:" \ + "sll (iy+#12),d:sll (iy+#12),e:sll (iy+#12),h:sll (iy+#12),l:sll (iy+#12):sll (iy+#12),a:" \ + "srl (iy+#12),b:srl (iy+#12),c:srl (iy+#12),d:srl (iy+#12),e:srl (iy+#12),h:srl (iy+#12),l:" \ + "srl (iy+#12):srl (iy+#12),a::bit 0,(iy+#12):bit 1,(iy+#12):bit 2,(iy+#12):bit 3,(iy+#12):" \ + "bit 4,(iy+#12):bit 5,(iy+#12):bit 6,(iy+#12):bit 7,(iy+#12)::res 0,(iy+#12),b:res 0,(iy+#12),c:" \ + "res 0,(iy+#12),d:res 0,(iy+#12),e:res 0,(iy+#12),h:res 0,(iy+#12),l:res 0,(iy+#12):" \ + "res 0,(iy+#12),a::res 1,(iy+#12),b:res 1,(iy+#12),c:res 1,(iy+#12),d:res 1,(iy+#12),e:" \ + "res 1,(iy+#12),h:res 1,(iy+#12),l:res 1,(iy+#12):res 1,(iy+#12),a::res 2,(iy+#12),b:" \ + "res 2,(iy+#12),c:res 2,(iy+#12),d:res 2,(iy+#12),e:res 2,(iy+#12),h:res 2,(iy+#12),l:" \ + "res 2,(iy+#12):res 2,(iy+#12),a::res 3,(iy+#12),b:res 3,(iy+#12),c:res 3,(iy+#12),d:" \ + "res 3,(iy+#12),e:res 3,(iy+#12),h:res 3,(iy+#12),l:res 3,(iy+#12):res 3,(iy+#12),a::" \ + "res 4,(iy+#12),b:res 4,(iy+#12),c:res 4,(iy+#12),d:res 4,(iy+#12),e:res 4,(iy+#12),h:" \ + "res 4,(iy+#12),l:res 4,(iy+#12):res 4,(iy+#12),a::res 5,(iy+#12),b:res 5,(iy+#12),c:" \ + "res 5,(iy+#12),d:res 5,(iy+#12),e:res 5,(iy+#12),h:res 5,(iy+#12),l:res 5,(iy+#12):" \ + "res 5,(iy+#12),a::res 6,(iy+#12),b:res 6,(iy+#12),c:res 6,(iy+#12),d:res 6,(iy+#12),e:" \ + "res 6,(iy+#12),h:res 6,(iy+#12),l:res 6,(iy+#12):res 6,(iy+#12),a::res 7,(iy+#12),b:" \ + "res 7,(iy+#12),c:res 7,(iy+#12),d:res 7,(iy+#12),e:res 7,(iy+#12),h:res 7,(iy+#12),l:" \ + "res 7,(iy+#12):res 7,(iy+#12),a::set 0,(iy+#12),b:set 0,(iy+#12),c:set 0,(iy+#12),d:" \ + "set 0,(iy+#12),e:set 0,(iy+#12),h:set 0,(iy+#12),l:set 0,(iy+#12):set 0,(iy+#12),a::" \ + "set 1,(iy+#12),b:set 1,(iy+#12),c:set 1,(iy+#12),d:set 1,(iy+#12),e:set 1,(iy+#12),h:" \ + "set 1,(iy+#12),l:set 1,(iy+#12):set 1,(iy+#12),a::set 2,(iy+#12),b:set 2,(iy+#12),c:" \ + "set 2,(iy+#12),d:set 2,(iy+#12),e:set 2,(iy+#12),h:set 2,(iy+#12),l:set 2,(iy+#12):" \ + "set 2,(iy+#12),a::set 3,(iy+#12),b:set 3,(iy+#12),c:set 3,(iy+#12),d:set 3,(iy+#12),e:" \ + "set 3,(iy+#12),h:set 3,(iy+#12),l:set 3,(iy+#12):set 3,(iy+#12),a::set 4,(iy+#12),b:" \ + "set 4,(iy+#12),c:set 4,(iy+#12),d:set 4,(iy+#12),e:set 4,(iy+#12),h:set 4,(iy+#12),l:" \ + "set 4,(iy+#12):set 4,(iy+#12),a::set 5,(iy+#12),b:set 5,(iy+#12),c:set 5,(iy+#12),d:" \ + "set 5,(iy+#12),e:set 5,(iy+#12),h:set 5,(iy+#12),l:set 5,(iy+#12):set 5,(iy+#12),a::" \ + "set 6,(iy+#12),b:set 6,(iy+#12),c:set 6,(iy+#12),d:set 6,(iy+#12),e:set 6,(iy+#12),h:" \ + "set 6,(iy+#12),l:set 6,(iy+#12):set 6,(iy+#12),a::set 7,(iy+#12),b:set 7,(iy+#12),c:" \ + "set 7,(iy+#12),d:set 7,(iy+#12),e:set 7,(iy+#12),h:set 7,(iy+#12),l:set 7,(iy+#12):" \ + "set 7,(iy+#12),a:" + +#define AUTOTEST_LABNUM "mavar=67:label{mavar}truc:ld hl,7+2*label{mavar}truc:mnt=1234567:lab2{mavar}{mnt}:" \ + "ld de,lab2{mavar}{mnt}:lab3{mavar}{mnt}h:ld de,lab3{mavar}{mnt}h" + +#define AUTOTEST_EQUNUM "mavar = 9:monlabel{mavar+5}truc:unalias{mavar+5}heu equ 50:autrelabel{unalias14heu}:ld hl,autrelabel50" + +#define AUTOTEST_DELAYNUM "macro test label: dw {label}: endm: repeat 3, idx:idx2 = idx-1:" \ + " test label_{idx2}: rend:repeat 3, idx:label_{idx-1}:nop:rend" + +#define AUTOTEST_STRUCT "org #1000:label1 :struct male:age defb 0:height defb 0:endstruct:struct female:" \ + "age defb 0:height defb 0:endstruct:struct couple:struct male husband:" \ + "struct female wife:endstruct:if $-label1!=0:stop:endif:ld a,(ix+couple.wife.age):" \ + "ld bc,couple:ld bc,{sizeof}couple:struct couple mycouple:" \ + "if mycouple.husband != mycouple.husband.age:stop:endif:ld hl,mycouple:" \ + "ld hl,mycouple.wife.age:ld bc,{sizeof}mycouple:macro cmplastheight p1:" \ + "ld hl,@mymale.height:ld a,{p1}:cp (hl):ld bc,{sizeof}@mymale:ld hl,@mymale:ret:" \ + "struct male @mymale:mend:cmplastheight 5:cmplastheight 3:nop" + +#define AUTOTEST_STRUCT2 "struct bite: preums defb 0: deuze defw 1: troize defs 10: endstruct:" \ + " if {sizeof}bite.preums!=1 || {sizeof}bite.deuze!=2 || {sizeof}bite.troize!=10: stop: endif: nop " + +#define AUTOTEST_REPEAT "ce=100:repeat 2,ce:repeat 5,cx:repeat 5,cy:defb cx*cy:rend:rend:rend:assert cx==6 && cy==6 && ce==3:" \ + "cpt=0:repeat:cpt=cpt+1:until cpt>4:assert cpt==5" + +#define AUTOTEST_REPEATKO "repeat 5:nop" + +#define AUTOTEST_WHILEKO "while 5:nop" + +#define AUTOTEST_TICKER "repeat 2: ticker start, mc:out (0),a:out (c),a:out (c),h:out (c),0:ticker stop, mc:if mc!=15:ld hl,bite:else:nop:endif:rend" + +#define AUTOTEST_ORG "ORG #8000,#1000:defw $:ORG $:defw $" + +#define AUTOTEST_BANKORG "bank 0:nop:org #5:nop:bank 1:unevar=10:bank 0:assert $==6:ret:bank 1:assert $==0:bank 0:assert $==7" + +#define AUTOTEST_VAREQU "label1 equ #C000:label2 equ (label1*2)/16:label3 equ label1-label2:label4 equ 15:var1=50*3+2:var2=12*label1:var3=label4-8:var4=label2:nop" + +#define AUTOTEST_FORMAT "hexa=#12A+$23B+45Ch+0x56D:deci=123.45+-78.54*2-(7-7)*2:bina=0b101010+1010b-%1111:assert hexa==3374 && deci==-33.63 && bina==37:nop" + +#define AUTOTEST_CHARSET "charset 'abcde',0:defb 'abcde':defb 'a','b','c','d','e':defb 'a',1*'b','c'*1,1*'d','e'*1:charset:" \ + "defb 'abcde':defb 'a','b','c','d','e':defb 'a',1*'b','c'*1,1*'d','e'*1" + +#define AUTOTEST_CHARSET2 "charset 97,97+26,0:defb 'roua':charset:charset 97,10:defb 'roua':charset 'o',5:defb 'roua':charset 'ou',6:defb 'roua'" + +#define AUTOTEST_NOCODE "let monorg=$:NoCode:Org 0:Element1 db 0:Element2 dw 3:Element3 ds 50:Element4 defb 'rdd':Org 0:pouet defb 'nop':" \ + "Code:Org monorg:cpt=$+element2+element3+element4:defs cpt,0" + +#define AUTOTEST_LZSEGMENT "org #100:debut:jr nz,zend:lz48:repeat 128:nop:rend:lzclose:jp zend:lz48:repeat 2:dec a:jr nz,@next:ld a,5:@next:jp debut:rend:" \ + "lzclose:zend" + +#define AUTOTEST_PAGETAG "bankset 0:org #5000:label1:bankset 1:org #9000:label2:bankset 2:" \ + "assert {page}label1==0x7FC0:assert {page}label2==0x7FC6:assert {pageset}label1==#7FC0:assert {pageset}label2==#7FC2:nop" + +#define AUTOTEST_PAGETAG2 "bankset 0:call maroutine:bank 4:org #C000:autreroutine:nop:" \ + "ret:bank 5:org #8000:maroutine:ldir:ret:bankset 2:org #9000:troize:nop:" \ + "assert {page}maroutine==#7FC5:assert {pageset}maroutine==#7FC2:assert {page}autreroutine==#7FC4:" \ + "assert {pageset}autreroutine==#7FC2:assert {page}troize==#7FCE:assert {pageset}troize==#7FCA" + +#define AUTOTEST_PAGETAG3 "buildsna:bank 2:assert {bank}$==2:assert {page}$==0x7FC0:assert {pageset}$==#7FC0:" \ + "bankset 1:org #4000:assert {bank}$==5:assert {page}$==0x7FC5:assert {pageset}$==#7FC2" + +#define AUTOTEST_SWITCH "mavar=4:switch mavar:case 1:nop:case 4:defb 4:case 3:defb 3:break:case 2:nop:case 4:defb 4:endswitch" + +#define AUTOTEST_PREPRO0 "\n\n\n\n;bitch\n\nnop\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nxor a\n\n\n\n\n\n\n\n\n\n\n\n" + +#define AUTOTEST_PREPRO1 " macro DEBUG_INK0, coul: out (c), a: endm: ifndef NDEBUG:DEBUG_BORDER_NOPS = 0: endif" + +#define AUTOTEST_PREPRO2 " nop : mycode other tartine ldir : defw tartine,other, mycode : assert tartine==other && other==mycode && mycode==1 && $==9" + +#define AUTOTEST_PREPRO3 "nop\n \n /* test ' ici */\n nop /* retest */ 5\n /* bonjour\n prout\n caca\n pipi */" \ + " nop\n nop /* nop */ : nop\n ; grouik /*\n \n /* ; pouet */ ld hl,#2121\n " + +#define AUTOTEST_PREPRO4 "glop=0\n nop ; glop=1\n assert glop==0\n nop\n glop=0\n nop // glop=1\n assert glop==0\n nop\n glop=0 : /* glop=1 */ nop\n" \ + "assert glop==0\n nop\n \n glop=0 : /* glop=1 // */ nop\n assert glop==0\n nop\n glop=0 : /* glop=1 ; */ nop\n" \ + "assert glop==0\n nop\n glop=0 ; /* glop=1\n nop // glop=2 /*\n assert glop==0\n nop\n" + +#define AUTOTEST_PROXIM "routine:.step1:jp .step2:.step2:jp .step1:deuze:nop:.step1:djnzn .step1:djnz routine.step2" + +#define AUTOTEST_TAGPRINT "unevar=12:print 'trucmuche{unevar}':print '{unevar}':print '{unevar}encore','pouet{unevar}{unevar}':ret" + +#define AUTOTEST_TAGFOLLOW "ret:uv=1234567890:unlabel_commeca_{uv} equ pouetpouetpouettroulala:pouetpouetpouettroulala:assert unlabel_commeca_{uv}>0" + +#define AUTOTEST_TAGREALLOC "zoomscroller_scroller_height equ 10: another_super_long_equ equ 256: pinouille_super_long_useless_equ equ 0: " \ + "zz equ 1111111111: org #100: repeat zoomscroller_scroller_height,idx: " \ + "zoomscroller_buffer_line_{idx-1}_{pinouille_super_long_useless_equ} nop: zoomscroller_buffer_line_{idx-1}_{zz} nop: " \ + "rend: align 256: repeat zoomscroller_scroller_height,idx: zoomscroller_buffer_line_{idx-1}_{pinouille_super_long_useless_equ}_duplicate nop: " \ + "zoomscroller_buffer_line_{idx-1}_{zz}_duplicate nop: rend: repeat zoomscroller_scroller_height, line: idx = line - 1: " \ + "assert zoomscroller_buffer_line_{idx}_{pinouille_super_long_useless_equ} + another_super_long_equ == "\ + "zoomscroller_buffer_line_{idx}_{pinouille_super_long_useless_equ}_duplicate: " \ + "assert zoomscroller_buffer_line_{idx}_{zz} + another_super_long_equ == zoomscroller_buffer_line_{idx}_{zz}_duplicate: rend" + +#define AUTOTEST_DEFUSED "ld hl,labelused :ifdef labelused:fail 'labelexiste':endif:ifndef labelused:else:fail 'labelexiste':endif:" \ + "ifnused labelused:fail 'labelused':endif:ifused labelused:else:fail 'labelused':endif:labelused" + +#define AUTOTEST_SAVEINVALID1 "nop : save'gruik',20,-100" + +#define AUTOTEST_SAVEINVALID2 "nop : save'gruik',-20,100" + +#define AUTOTEST_SAVEINVALID3 "nop : save'gruik',40000,30000" + +#define AUTOTEST_MACROPROX " macro unemacro: nop: endm: global_label: ld hl, .table: .table" + +#define AUTOTEST_PROXBACK " macro grouik: @truc djnz @truc: .unprox djnz .unprox: mend:" \ + "ld b,2: unglobal nop: djnz unglobal: ld b,2: .unprox nop: djnz .unprox: beforelocal=$ :" \ + "repeat 2: @unlocal: ld b,2: .unprox nop: djnz .unprox: grouik : djnz .unprox : rend: assert .unprox < beforelocal : nop" +#define AUTOTEST_LOCAPROX "repeat 1: @label nop: .prox nop: @label2 nop: djnz @label.prox: rend" + +#define AUTOTEST_QUOTES "defb 'rdd':str 'rdd':charset 'rd',0:defb '\\r\\d':str '\\r\\d'" + +#define AUTOTEST_NEGATIVE "ld a,-5: ld bc,-0x3918:ld de,0+-#3918:ld de,-#3918:var1=-5+6:var2=-#3918+#3919:assert var1+var2==2" + +#define AUTOTEST_FORMULA1 "a=5:b=2:assert int(a/b)==3:assert !a+!b==0:a=a*100:b=b*100:assert a*b==100000:ld hl,a*b-65536:a=123+-5*(-6/2)-50*2<<1" + +#define AUTOTEST_FORMULA2 "vala= (0.5+(4*0.5))*6:valb= int((0.5+(4*0.5))*6):nop:if vala!=valb:push erreur:endif" + +#define AUTOTEST_FRAC "mavar=frac(5.5):assert mavar==0.5:assert frac(6.6)==0.6:assert frac(1.1)==0.1:assert frac(1)==0:assert frac(100000)==0:nop" + +/* test override control between bank and bankset in snapshot mode + temp workspace */ +#define AUTOTEST_BANKSET "buildsna:bank 0:nop:bank 1:nop:bank:nop:bank 2:nop:bank 3:nop:bankset 1:nop:bank 8:nop:bank 9:nop:bank 10:nop:bank 11:nop" + +#define AUTOTEST_LIMITOK "org #100:limit #102:nop:limit #103:ld a,0:protect #105,#107:limit #108:xor a:org $+3:inc a" + +#define AUTOTEST_LIMITKO "limit #100:org #100:add ix,ix" + +#define AUTOTEST_DEFS "defs 256,0" + +#define AUTOTEST_LIMIT03 "limit -1 : nop" +#define AUTOTEST_LIMIT04 "limit #10000 : nop" +#define AUTOTEST_LIMIT05 "org #FFFF : ldir" +#define AUTOTEST_LIMIT06 "org #FFFF : nop" + +#define AUTOTEST_LIMIT07 "org #ffff : Start: equ $ : di : ld hl,#c9fb : ld (#38),hl" + +#define AUTOTEST_DELAYED_RUN "run _start:nop:_start nop" + +#define AUTOTEST_INHIBITION "if 0:ifused truc:ifnused glop:ifdef bidule:ifndef machin:ifnot 1:nop:endif:nop:else:nop:endif:endif:endif:endif:endif" + +#define AUTOTEST_LZ4 "lz4:repeat 10:nop:rend:defb 'roudoudoudouoneatxkjhgfdskljhsdfglkhnopnopnopnop':lzclose" + +#define AUTOTEST_MAXERROR "repeat 20:aglapi:rend:nop" + +#define AUTOTEST_ENHANCED_LD "ld h,(ix+11): ld l,(ix+10): ld h,(iy+21): ld l,(iy+20): ld b,(ix+11): ld c,(ix+10):" \ + "ld b,(iy+21): ld c,(iy+20): ld d,(ix+11): ld e,(ix+10): ld d,(iy+21): ld e,(iy+20): ld hl,(ix+10): " \ + "ld hl,(iy+20):ld bc,(ix+10):ld bc,(iy+20): ld de,(ix+10):ld de,(iy+20)" + +#define AUTOTEST_ENHANCED_PUSHPOP "push bc,de,hl,ix,iy,af:pop hl,bc,de,iy,ix,af:nop 2:" \ + "push bc:push de:push hl:push ix:push iy:push af:"\ + "pop hl:pop bc:pop de:pop iy:pop ix:pop af:nop:nop" +#define AUTOTEST_ENHANCED_LD2 "ld (ix+0),hl: ld (ix+0),de: ld (ix+0),bc: ld (iy+0),hl: ld (iy+0),de: ld (iy+0),bc:"\ +"ld (ix+1),h: ld (ix+0),l: ld (ix+1),d: ld (ix+0),e: ld (ix+1),b: ld (ix+0),c: ld (iy+1),h: ld (iy+0),l: ld (iy+1),d: ld (iy+0),e: ld (iy+1),b: ld (iy+0),c" + +#define AUTOTEST_INHIBITION2 "ifdef roudoudou:macro glop bank,page,param:ld a,{bank}:ld hl,{param}{bank}:if {bank}:nop:else:exx:" \ + "endif::switch {param}:nop:case 4:nop:case {param}:nop:default:nop:break:endswitch:endif:defb 'coucou'" + +#define AUTOTEST_INHIBITIONMAX "roudoudou:ifndef roudoudou:if pouet:macro glop bank,page,param:ifdef nanamouskouri:ld hl,{param}{bank}:"\ + "elseif aglapi:exx:endif:if {bank}:nop:elseif {grouik}:exx:endif:switch {bite}:nop:case {nichon}:nop:default:nop:break:endswitch:else:"\ + "ifnot {jojo}:exx:endif:endif:else:defb 'coucou':endif" + +#define AUTOTEST_NOEXPORT "unlabel nop:.unlocal nop:unevar=5:unequ equ 10:noexport unlabel, .unlocal, "\ + "unlabel.unlocal, unevar, unequ:enoexport unlabel, .unlocal, unlabel.unlocal, unevar, unequ" + +#define AUTOTEST_UNDERVAR "coucou nop:_coucou nop:_mavar=5:jr _coucou+_mavar:print _mavar" + +#define AUTOTEST_CODESKIP "org #100: nop: old_dollar=$: nocode: defs 10: assert $==old_dollar+10: code: "\ + "assert $==old_dollar+10: org #200: nop: old_dollar=$: nocode: defs 10: assert $==old_dollar+10: code skip: assert $==old_dollar" + +#define AUTOTEST_EMBEDDED_ERRORS "nop : rien : rien : rien : glop nop : glapi nop" + +#define AUTOTEST_EMBEDDED_LABELS " disarkCounter = 0:MACRO dkps:PLY_AKG_DisarkPointerRegionStart_{disarkCounter}:ENDM" \ + ":MACRO dkpe\nPLY_AKG_DisarkPointerRegionEnd_{disarkCounter}:\ndisarkCounter = disarkCounter + 1:ENDM:\ndkps\ndkpe\ndkps" + +#define AUTOTEST_TAGLOOP "tab1 = #100:tab2 = #200:tab3 = #300:macro genreg channel,psg:label{channel} EQU tab{psg} + channeloffset:"\ + "endm:channel=1:while channel <= 9:psg=floor(((channel-1)/3)+1):channeloffset=((channel-1) % 3)*2:"\ + "genreg {channel},{psg}:channel=channel+1:wend:assert LABEL5==#0202:assert LABEL6==#0204:assert LABEL7==#0300:"\ + "assert LABEL8==#0302:nop" + +#define AUTOTEST_PLUSCOLOR " myval=0x123 : assert getr(myval)==2 : assert getb(myval)==3 : assert getg(myval)==1 : assert getv(myval)==1" \ + " : assert setr(2)+setv(1)+setb(3)==0x123 : assert setv(-2)==setv(0) && setb(220)==setb(15) : nop " + +#define AUTOTEST_ASSERT " macro zem,nom,adr: overflow equ $-{adr}: assert $<{adr},{nom}: nop: mend: zem 'bidule',#2FFF :" \ + " macro zem2,nom,adr: overflow2 equ $-{adr}: assert $<{adr},{nom},{adr},overflow2: nop: mend: zem2 'bidule',#2FFF :" \ + " macro zem3,nom,adr: overflow3 equ $-{adr}: assert $<{adr},{nom},{hex}{adr},overflow3: nop: mend: zem3 'bidule',#2FFF " + + +struct s_autotest_keyword { + char *keywordtest; + int result; +}; + +struct s_autotest_keyword autotest_keyword[]={ + {"ld ly,h",1}, {"ld lx,h",1}, {"ld ly,l",1}, {"ld lx,l",1}, {"ld hy,h",1}, {"ld hx,h",1}, {"ld hy,l",1}, {"ld hx,l",1}, + {"nop",0},{"nop 2",0},{"nop a",1},{"nop (hl)",1},{"nop nop",1},{"nop grouik",1}, + {"ldir",0},{"ldir 5",1},{"ldir ldir",1},{"ldir (hl)",1},{"ldir a",1},{"ldir grouik",1}, + {"ldi",0},{"ldi 5",1},{"ldi ldi",1},{"ldi (hl)",1},{"ldi a",1},{"ldi grouik",1}, + {"lddr",0},{"lddr 5",1},{"lddr lddr",1},{"lddr (hl)",1},{"lddr a",1},{"lddr groudk",1}, + {"ldd",0},{"ldd 5",1},{"ldd ldd",1},{"ldd (hl)",1},{"ldd a",1},{"ldd groudk",1}, + {"jr $",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, + {"jr c,$",0},{"jr c,0",0},{"jr c,jr",1},{"jr c,(hl)",1},{"jr c,a",1}, + {"jr nc,$",0},{"jr nc,0",0},{"jr nc,jr",1},{"jr nc,(hl)",1},{"jr nc,a",1}, + {"jr z,$",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, + {"jr nz,$",0},{"jr 0",0},{"jr jr",1},{"jr (hl)",1},{"jr a",1}, + {"jp $",0},{"jp 0",0},{"jp jp",1},{"jp (hl)",0},{"jp (ix)",0},{"jp (iy)",0},{"jp (de)",1},{"jp a",1}, + {"jp c,$",0},{"jp c,0",0},{"jp c,jp",1}, {"jp c,(hl)",1}, {"jp c,(ix)",1}, {"jp c,(iy)",1},{"jp c,(de)",1},{"jp c,a",1}, + {"jp nc,$",0},{"jp nc,0",0},{"jp nc,jp",1},{"jp nc,(hl)",1},{"jp nc,(ix)",1},{"jp nc,(iy)",1},{"jp nc,(de)",1},{"jp nc,a",1}, + {"jp z,$",0},{"jp z,0",0},{"jp z,jp",1}, {"jp z,(hl)",1}, {"jp z,(ix)",1}, {"jp z,(iy)",1},{"jp z,(de)",1},{"jp z,a",1}, + {"jp nz,$",0},{"jp nz,0",0},{"jp nz,jp",1},{"jp nz,(hl)",1},{"jp nz,(ix)",1},{"jp nz,(iy)",1},{"jp nz,(de)",1},{"jp nz,a",1}, + {"jp pe,$",0},{"jp pe,0",0},{"jp pe,jp",1},{"jp pe,(hl)",1},{"jp pe,(ix)",1},{"jp pe,(iy)",1},{"jp pe,(de)",1},{"jp pe,a",1}, + {"jp po,$",0},{"jp po,0",0},{"jp po,jp",1},{"jp po,(hl)",1},{"jp po,(ix)",1},{"jp po,(iy)",1},{"jp po,(de)",1},{"jp po,a",1}, + {"jp p,$",0},{"jp p,0",0},{"jp p,jp",1}, {"jp p,(hl)",1}, {"jp p,(ix)",1}, {"jp p,(iy)",1},{"jp p,(de)",1},{"jp p,a",1}, + {"jp m,$",0},{"jp m,0",0},{"jp m,jp",1}, {"jp m,(hl)",1}, {"jp m,(ix)",1}, {"jp m,(iy)",1},{"jp m,(de)",1},{"jp m,a",1}, + {"ret",0},{"ret c",0},{"ret nc",0},{"ret pe",0},{"ret po",0},{"ret m",0},{"ret p",0},{"reti",0},{"ret ret",1},{"ret 5",1},{"ret (hl)",1},{"ret a",1}, + {"xor a",0},{"xor a,b",1},{"xor",1},{"xor (de)",1},{"xor (hl)",0},{"xor (bc)",1},{"xor (ix+0)",0},{"xor (iy+0)",},{"xor xor",1}, + {"and a",0},{"and a,b",1},{"xor",1},{"and (de)",1},{"and (hl)",0},{"and (bc)",1},{"and (ix+0)",0},{"and (iy+0)",},{"and xor",1}, + {"or a",0},{"or a,b",1},{"xor",1},{"or (de)",1},{"or (hl)",0},{"or (bc)",1},{"or (ix+0)",0},{"or (iy+0)",},{"or xor",1}, + {"add",1},{"add a",0},{"add a,a",0},{"add add",1},{"add (hl)",0},{"add (de)",1},{"add xh",0},{"add grouik",1}, + {"add hl,ix",1},{"add hl,iy",1},{"add ix,iy",1},{"add iy,ix",1},{"add hl,0",1},{"add hl,grouik",1},{"add ix,hl",1},{"add iy,hl",1}, + {"adc",1},{"adc a",0},{"adc a,a",0},{"adc adc",1},{"adc (hl)",0},{"adc (de)",1},{"adc xh",0},{"adc grouik",1}, + {"adc hl,ix",1},{"adc hl,iy",1},{"adc ix,iy",1},{"adc iy,ix",1},{"adc hl,0",1},{"adc hl,grouik",1},{"adc ix,hl",1},{"adc iy,hl",1}, + {"sub",1},{"sub a",0},{"sub a,a",0},{"sub sub",1},{"sub (hl)",0},{"sub (de)",1},{"sub xh",0},{"sub grouik",1}, + {"sub hl,ix",1},{"sub hl,iy",1},{"sub ix,iy",1},{"sub iy,ix",1},{"sub hl,0",1},{"sub hl,grouik",1},{"sub ix,hl",1},{"sub iy,hl",1}, + {"sbc",1},{"sbc a",0},{"sbc a,a",0},{"sbc sbc",1},{"sbc (hl)",0},{"sbc (de)",1},{"sbc xh",0},{"sbc grouik",1}, + {"sbc hl,ix",1},{"sbc hl,iy",1},{"sbc ix,iy",1},{"sbc iy,ix",1},{"sbc hl,0",1},{"sbc hl,grouik",1},{"sbc ix,hl",1},{"sbc iy,hl",1}, + {"exx",0},{"exx hl",1},{"exx hl,de",1},{"exx af,af'",1},{"exx exx",1},{"exx 5",1}, + {"ex",1},{"ex af,af'",0},{"ex hl,de",0},{"ex hl,bc",1},{"ex hl,hl",1},{"ex hl,ix",1}, + {"cp",1},{"cp cp ",1},{"cp 5",0},{"cp c",0},{"cp a,5",0},{"cp a,c",0},{"cp hl",1},{"cp (hl)",0},{"cp a,(hl)",0},{"cp (de)",1},{"cp de",1}, + {"cpi",0},{"cpi (hl)",1},{"cpi a",1},{"cpi 5",1}, + {"cpd",0},{"cpd (hl)",1},{"cpd a",1},{"cpd 5",1}, + {"cpir",0},{"cpir (hl)",1},{"cpir a",1},{"cpir 5",1}, + {"cpdr",0},{"cpdr (hl)",1},{"cpdr a",1},{"cpdr 5",1}, + {"call #1234",0},{"call call",1},{"call (hl)",1},{"call (ix)",1},{"call (iy)",1},{"call (de)",1},{"call hl",1},{"call bc",1},{"call a",1},{"call 5,5",1}, + {"rst 5",1},{"rst",1},{"rst 0",0},{"rst rst",1},{"rst (hl)",1},{"rst (ix)",1},{"rst (iy)",1},{"rst z",1},{"rst z,0",1}, + {"djnz",1},{"djnz $",0},{"djnz $,0",1},{"djnz djnz",1},{"djnz (hl)",1}, + {"djnz (ix)",1},{"djnz (iy)",1},{"djnz (bc)",1},{"djnz bc",1},{"djnz ix",1},{"djnz iy",1},{"djnz hl",1}, + {"push",1},{"push push",1},{"push pop",1},{"push af'",1},{"push (ix)",1},{"push (hl)",1},{"push (#1234)",1},{"push #1234",1}, + {"pop",1},{"pop pop",1},{"pop push",1},{"pop af'",1},{"pop (ix)",1},{"pop (hl)",1},{"pop (#1234)",1},{"pop #1234",1}, + {"set -1,a",1},{"set 9,a",1},{"set 0,xh",1},{"set 0,ix",1},{"set 0",1},{"set",1},{"set set",1},{"set 0,a,a",1},{"set 0,(ix+0),xh",1}, + {"bit -1,a",1},{"bit 9,a",1},{"bit 0,xh",1},{"bit 0,ix",1},{"bit 0",1},{"bit",1},{"bit bit",1},{"bit 0,a,a",1},{"bit 0,(ix+0),xh",1}, + {"res -1,a",1},{"res 9,a",1},{"res 0,xh",1},{"res 0,ix",1},{"res 0",1},{"res",1},{"res res",1},{"res 0,a,a",1},{"res 0,(ix+0),xh",1}, + {"srl",1},{"srl srl",1},{"srl hl",0}, /* srl hl is a kind of macro */ + {"rld a",1},{"rld (hl)",1},{"rld rld",1},{"rld 5",1},{"rld (ix)",1}, + {"rrd a",1},{"rrd (hl)",1},{"rrd rrd",1},{"rrd 5",1},{"rrd (ix)",1}, + {"cpl a",1},{"cpl (hl)",1},{"cpl cpl",1},{"cpl 0",1}, + {"daa daa daa",1},{"daa 0",1},{"daa (hl)",1}, + {"scf scf",1},{"scf 0",1},{"scf (hl)",1}, + {"ccf ccf",1},{"ccf 0",1},{"ccf (hl)",1}, + {"out",1},{"out out",1},{"out (c)",1},{"out (c),xh",1},{"out 0",1}, + {"out (c),hl",1},{"out (hl),c",1},{"out (c),(ix+0)",1},{"out (c),a,b",1}, + {"outi 0",1},{"outi (hl)",1}, + {"otir 0",1},{"otir (hl)",1}, + {"otdr 0",1},{"otdr (hl)",1}, + {"outd 0",1},{"outd (hl)",1}, + {"in",1},{"in in",1},{"in (c)",1},{"in xh,(c)",1},{"in 0",1}, + {"in hl,(c)",1},{"in c,(hl)",1},{"in (c),(ix+0)",1},{"in a,(c),b",1}, + {"ini 0",1},{"ini (hl)",1}, + {"inir 0",1},{"inir (hl)",1}, + {"indr 0",1},{"indr (hl)",1}, + {"ind 0",1},{"ind (hl)",1}, + {"di 5",1},{"di di",1},{"di hl",1},{"di a",1}, + {"ei 5",1},{"ei ei",1},{"ei hl",1},{"ei a",1}, + {"im",1},{"im 3",1},{"im -1",1},{"im (hl)",1}, + {"halt 5",1},{"reti 5",1},{"retn 5",1},{"ld i,b",1},{"ld b,i",1}, + + {"repeat 5:nop:rend",0},{"repeat 100000:a=5:rend",1},{"repeat -5:nop:rend",1},{"repeat repeat:nop:rend",1}, + {"macro bidule:nop:mend:bidule",0},{"macro bidule:nop:macro glop:nop:mend:mend:bidule",1}, + {"macro bidule:nop",1},{"macro bidule:nop:mend:macro glop:nop:bidule",1}, + /* + {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, + {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, + {"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",},{"",}, + */ + {NULL,0} +}; + +void MiniDump(unsigned char *opcode, int opcodelen) { + #undef FUNC + #define FUNC "MiniDump" + + int i; + printf("%d byte%s to dump\n",opcodelen,opcodelen>1?"s":""); + for (i=0;i<opcodelen;i++) { + printf("%02X \n",opcode[i]); + } + printf("\n"); +} + +void RasmAutotest(void) +{ + #undef FUNC + #define FUNC "RasmAutotest" + + struct s_rasm_info *debug; + unsigned char *opcode=NULL; + int opcodelen,ret,filelen; + int cpt=0,chk,i,idx; + char tmpstr1[256],tmpstr2[256],*tmpstr3,**tmpsplit; + +#ifdef RDD + printf("\n%d bytes\n",_static_library_memory_used); +#endif +#if 0 + /* Autotest CORE */ + #ifdef OS_WIN + printf(".");fflush(stdout); + strcpy(tmpstr1,".\\archives\\job.asm"); + strcpy(tmpstr2,".\\archives\\job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath0) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,".\\archives\\..\\job.asm"); + strcpy(tmpstr2,".\\job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath1) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,".\\archives\\gruik\\..\\..\\job.asm"); + strcpy(tmpstr2,".\\job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath2) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,".\\archives\\..\\gruik\\..\\job.asm"); + strcpy(tmpstr2,".\\job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath3) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"..\\archives\\job.asm"); + strcpy(tmpstr2,"..\\archives\\job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath4) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,".\\src\\..\\..\\src\\job.asm"); + strcpy(tmpstr2,"..\\src\\job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath5) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"src\\..\\..\\src\\job.asm"); + strcpy(tmpstr2,"..\\src\\job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath6) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + cpt++; + #else + printf(".");fflush(stdout); + strcpy(tmpstr1,"./archives/job.asm"); + strcpy(tmpstr2,"./archives/job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath0) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"./archives/../job.asm"); + strcpy(tmpstr2,"./job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath1) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"./archives/gruik/../../job.asm"); + strcpy(tmpstr2,"./job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath2) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"./archives/../gruik/../job.asm"); + strcpy(tmpstr2,"./job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath3) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"../archives/job.asm"); + strcpy(tmpstr2,"../archives/job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath4) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"./src/../../src/job.asm"); + strcpy(tmpstr2,"../src/job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath5) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + strcpy(tmpstr1,"src/../../../src/job.asm"); + strcpy(tmpstr2,"../../src/job.asm"); + SimplifyPath(tmpstr1);if (strcmp(tmpstr1,tmpstr2)) {printf("Autotest %03d ERROR (Core:SimplifyPath6) %s!=%s\n",cpt,tmpstr1,tmpstr2);exit(-1);} + cpt++; + printf(".");fflush(stdout); + if (strcmp(GetPath("/home/roudoudou/"),"/home/roudoudou/")) {printf("Autotest %03d ERROR (Core:GetPath0) [%s]\n",cpt,GetPath("/home/roudoudou/"));exit(-1);} + if (strcmp(GetPath("/home/roudoudou"),"/home/")) {printf("Autotest %03d ERROR (Core:GetPath1) [%s]\n",cpt,GetPath("/home/roudoudou"));exit(-1);} + cpt++; + #endif +#endif + + /* Autotest preprocessing */ + ret=RasmAssemble(AUTOTEST_VIRGULE,strlen(AUTOTEST_VIRGULE),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (double comma must trigger an error) ret=%d\n",cpt,ret);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing preprocessor comma management in a string OK\n"); + + ret=RasmAssemble(AUTOTEST_VIRGULE2,strlen(AUTOTEST_VIRGULE2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (double comma in a string must be OK)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing preprocessor comma management in a string OK\n"); + + ret=RasmAssemble(AUTOTEST_PREPRO0,strlen(AUTOTEST_PREPRO0),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (uninitialize memory read!)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing preprocessor non regression OK\n"); + + ret=RasmAssemble(AUTOTEST_PREPRO1,strlen(AUTOTEST_PREPRO1),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (freestyle case 1)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing preprocessor freestyle OK\n"); + + ret=RasmAssemble(AUTOTEST_PREPRO2,strlen(AUTOTEST_PREPRO2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (freestyle case 2)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing preprocessor freestyle variation 2 OK\n"); + + ret=RasmAssemble(AUTOTEST_PREPRO3,strlen(AUTOTEST_PREPRO3),&opcode,&opcodelen); + if (!ret && opcodelen==12 && opcode[11]==0x21) {} else {printf("Autotest %03d ERROR (multi-line comment)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing multi-line comments 1 OK\n"); + + ret=RasmAssemble(AUTOTEST_PREPRO4,strlen(AUTOTEST_PREPRO4),&opcode,&opcodelen); + if (!ret && opcodelen==12) {} else {printf("Autotest %03d ERROR (multi-line comment 2)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing multi-line comments 2 OK\n"); + + ret=RasmAssemble(AUTOTEST_OPERATOR_CONVERSION,strlen(AUTOTEST_OPERATOR_CONVERSION),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (maxam operator conversion)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing Maxam operator conversion OK\n"); + + ret=RasmAssemble(AUTOTEST_OPERATOR_MODULO,strlen(AUTOTEST_OPERATOR_MODULO),&opcode,&opcodelen); + if (!ret && opcodelen==1) {} else {printf("Autotest %03d ERROR (modulo operator conversion)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing modulo operator conversion OK\n"); + + ret=RasmAssemble(AUTOTEST_NOINCLUDE,strlen(AUTOTEST_NOINCLUDE),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (include missing file)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("include on a missing file OK\n"); + + ret=RasmAssemble(AUTOTEST_FORMAT,strlen(AUTOTEST_FORMAT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (digit formats)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing digit formats OK\n"); + + /* Autotest assembling */ + ret=RasmAssemble(AUTOTEST_OPCODES,strlen(AUTOTEST_OPCODES),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (all opcodes)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing all opcodes OK\n"); + + /* Autotest single instruction writes that must failed */ + tmpstr3=TxtStrDup(AUTOTEST_INSTRMUSTFAILED); + tmpsplit=TxtSplitWithChar(tmpstr3,':'); + + for (i=0;tmpsplit[i];i++) { + ret=RasmAssemble(tmpsplit[i],strlen(tmpsplit[i]),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (opcodes that must fail) -> [%s]\n",cpt,tmpsplit[i]);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL; + } + + MemFree(tmpstr3);FreeFields(tmpsplit); + cpt++; +printf("testing various opcode tests OK\n"); + + idx=0; + while (autotest_keyword[idx].keywordtest) { + ret=RasmAssemble(autotest_keyword[idx].keywordtest,strlen(autotest_keyword[idx].keywordtest),&opcode,&opcodelen); + if (!ret && !autotest_keyword[idx].result) { + } else if (ret && autotest_keyword[idx].result) { + } else { + printf("Autotest %03d ERROR ([%s] test) is %s instead of %s\n",cpt,autotest_keyword[idx].keywordtest,!ret?"ok":"ko",ret?"ok":"ko"); + } + if (opcode) MemFree(opcode);opcode=NULL; + idx++; + } + cpt++; +printf("testing moar various opcode tests OK\n"); + + ret=RasmAssemble(AUTOTEST_ORG,strlen(AUTOTEST_ORG),&opcode,&opcodelen); + if (!ret && opcodelen==4 && opcode[1]==0x80 && opcode[2]==2 && opcode[3]==0x10) {} else {printf("Autotest %03d ERROR (ORG relocation)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing ORG relocation OK\n"); + + ret=RasmAssemble(AUTOTEST_MAXERROR,strlen(AUTOTEST_MAXERROR),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (must return an error code!)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing error code OK\n"); + + ret=RasmAssemble(AUTOTEST_BANKORG,strlen(AUTOTEST_BANKORG),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (BANK org adr)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing BANK/ORG OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMITOK,strlen(AUTOTEST_LIMITOK),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (limit ok)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LIMIT 1 OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMITKO,strlen(AUTOTEST_LIMITKO),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (out of limit)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LIMIT 2 OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT03,strlen(AUTOTEST_LIMIT03),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: negative limit)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing inegative LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT04,strlen(AUTOTEST_LIMIT04),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: max limit test)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing max LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT05,strlen(AUTOTEST_LIMIT05),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: ldir in #FFFF)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing 16 bits opcode overriding LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT06,strlen(AUTOTEST_LIMIT06),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (limit: nop in #FFFF)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing opcode overriding LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_LIMIT07,strlen(AUTOTEST_LIMIT07),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (limit: ld hl,#1234 in #FFFF)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing opcode with variable overriding LIMIT OK\n"); + + ret=RasmAssemble(AUTOTEST_DELAYED_RUN,strlen(AUTOTEST_DELAYED_RUN),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (delayed RUN set)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing delayed RUN OK\n"); + + ret=RasmAssemble(AUTOTEST_LZSEGMENT,strlen(AUTOTEST_LZSEGMENT),&opcode,&opcodelen); + if (!ret && opcodelen==23 && opcode[1]==21 && opcode[9]==23) {} else {printf("Autotest %03d ERROR (LZ segment relocation)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LZ segment relocation OK\n"); + + ret=RasmAssemble(AUTOTEST_LZ4,strlen(AUTOTEST_LZ4),&opcode,&opcodelen); + if (!ret && opcodelen==49 && opcode[0]==0x15 && opcode[4]==0x44 && opcode[0xB]==0xF0) {} else {printf("Autotest %03d ERROR (LZ4 segment)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing LZ4 segment OK\n"); + + ret=RasmAssemble(AUTOTEST_DEFS,strlen(AUTOTEST_DEFS),&opcode,&opcodelen); + if (!ret && opcodelen==256 && opcode[0]==0) {} else {printf("Autotest %03d ERROR (defs)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing DEFS OK\n"); + + ret=RasmAssemble(AUTOTEST_BANKSET,strlen(AUTOTEST_BANKSET),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (bank/bankset)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing BANK/BANKSET OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGETAG,strlen(AUTOTEST_PAGETAG),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing prefix PAGE/PAGESET 1 OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGETAG2,strlen(AUTOTEST_PAGETAG2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset 2)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing prefix PAGE/PAGESET 2 OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGETAG3,strlen(AUTOTEST_PAGETAG3),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (page/pageset 3)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing prefix PAGE/PAGESET 3 OK\n"); + + ret=RasmAssemble(AUTOTEST_UNDEF,strlen(AUTOTEST_UNDEF),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (simple undef)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing UNDEF OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGPRINT,strlen(AUTOTEST_TAGPRINT),&opcode,&opcodelen); + if (!ret && opcodelen==1 && opcode[0]==0xC9) {} else {printf("Autotest %03d ERROR (tag inside printed string)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing tags inside printed string OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGFOLLOW,strlen(AUTOTEST_TAGFOLLOW),&opcode,&opcodelen); + if (!ret && opcodelen==1 && opcode[0]==0xC9) {} else {printf("Autotest %03d ERROR (tag+alias fast translating)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing tag+alias in fast translate OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGREALLOC,strlen(AUTOTEST_TAGREALLOC),&opcode,&opcodelen); + if (!ret && opcodelen==276) {} else {printf("Autotest %03d ERROR (tag realloc with fast translate)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing tag realloc with fast translate OK\n"); + + ret=RasmAssemble(AUTOTEST_TAGLOOP,strlen(AUTOTEST_TAGLOOP),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (generated alias inside loop with generated var names )\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing generated alias inside loop with generated var names OK\n"); + + ret=RasmAssemble(AUTOTEST_PRINTVAR,strlen(AUTOTEST_PRINTVAR),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (param inside printed string)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing param inside printed string OK\n"); + + ret=RasmAssemble(AUTOTEST_PRINTSPACE,strlen(AUTOTEST_PRINTSPACE),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (space inside tag string for PRINT directive)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing space inside tag string for PRINT directive OK\n"); + + ret=RasmAssemble(AUTOTEST_INHIBITION,strlen(AUTOTEST_INHIBITION),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (conditionnal inhibition)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing conditionnal inhibition OK\n"); + + ret=RasmAssemble(AUTOTEST_SWITCH,strlen(AUTOTEST_SWITCH),&opcode,&opcodelen); + if (!ret && opcodelen==3 && opcode[0]==4 && opcode[1]==3 && opcode[2]==4) {} else {printf("Autotest %03d ERROR (switch case)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing SWITCH/CASE OK\n"); + + ret=RasmAssemble(AUTOTEST_NOCODE,strlen(AUTOTEST_NOCODE),&opcode,&opcodelen); + if (!ret && opcodelen==57) {} else {printf("Autotest %03d ERROR (code/nocode)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing code/nocode OK\n"); + + ret=RasmAssemble(AUTOTEST_VAREQU,strlen(AUTOTEST_VAREQU),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (var & equ)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing var & equ OK\n"); + + ret=RasmAssemble(AUTOTEST_CHARSET,strlen(AUTOTEST_CHARSET),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} + if (opcodelen!=30 || memcmp(opcode,opcode+5,5) || memcmp(opcode+10,opcode+5,5)) {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} + if (memcmp(opcode+15,opcode+20,5) || memcmp(opcode+15,opcode+25,5)) {printf("Autotest %03d ERROR (simple charset)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing simple charset OK\n"); + + ret=RasmAssemble(AUTOTEST_CHARSET2,strlen(AUTOTEST_CHARSET2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (extended charset)\n",cpt);exit(-1);} + for (i=chk=0;i<opcodelen;i++) chk+=opcode[i]; + if (opcodelen!=16 || chk!=0x312) {printf("Autotest %03d ERROR (extended charset)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing extended charset OK\n"); + + ret=RasmAssemble(AUTOTEST_QUOTES,strlen(AUTOTEST_QUOTES),&opcode,&opcodelen); + if (!ret && opcodelen==10 && opcode[5]==0xE4 && opcode[6]==0x0D && opcode[7]==0x64 && opcode[8]==0x0D && opcode[9]==0xE4) {} + else {printf("Autotest %03d ERROR (quotes & escaped chars)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing quoted & escaped chars OK\n"); + + ret=RasmAssemble(AUTOTEST_NOT,strlen(AUTOTEST_NOT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (not operator)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing NOT operator OK\n"); + + ret=RasmAssemble(AUTOTEST_MACRO,strlen(AUTOTEST_MACRO),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (macro usage)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing macro usage OK\n"); + + ret=RasmAssemble(AUTOTEST_ASSERT,strlen(AUTOTEST_ASSERT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (assert usage)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing assert usage (+prepro regression cases) OK\n"); + + ret=RasmAssemble(AUTOTEST_MACROPAR,strlen(AUTOTEST_MACROPAR),&opcode,&opcodelen); + if (!ret && opcodelen==12 && memcmp(opcode,"GROUIKgrouik",12)==0) {} else {printf("Autotest %03d ERROR (macro string param)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing macro string parameter OK\n"); + + ret=RasmAssemble(AUTOTEST_MACRO_ADV,strlen(AUTOTEST_MACRO_ADV),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (macro param)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing macro parameters OK\n"); + + ret=RasmAssemble(AUTOTEST_OVERLOADMACPRM,strlen(AUTOTEST_OVERLOADMACPRM),&opcode,&opcodelen); + if (!ret && opcodelen==4 && opcode[0]==1 && opcode[1]==0 && opcode[2]==2 && opcode[3]==1) {} else {printf("Autotest %03d ERROR (macro param overload)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing macro parameter overload OK\n"); + + ret=RasmAssemble(AUTOTEST_IFDEFMACRO,strlen(AUTOTEST_IFDEFMACRO),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (ifdef macro)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing IFDEF & MACRO OK\n"); + + ret=RasmAssemble(AUTOTEST_LABNUM,strlen(AUTOTEST_LABNUM),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (variables in labels)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing variables in labels OK\n"); + + ret=RasmAssemble(AUTOTEST_EQUNUM,strlen(AUTOTEST_EQUNUM),&opcode,&opcodelen); + if (!ret && opcodelen==3) {} else {printf("Autotest %03d ERROR (variables in aliases) r=%d l=%d\n",cpt,ret,opcodelen);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing variables in aliases OK\n"); + + ret=RasmAssemble(AUTOTEST_DELAYNUM,strlen(AUTOTEST_DELAYNUM),&opcode,&opcodelen); + if (!ret && opcodelen==9 && opcode[0]==6 && opcode[2]==7 && opcode[4]==8) {} else {printf("Autotest %03d ERROR (delayed expr labels) r=%d l=%d\n",cpt,ret,opcodelen);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing delayed expression labels OK\n"); + + ret=RasmAssemble(AUTOTEST_PROXIM,strlen(AUTOTEST_PROXIM),&opcode,&opcodelen); + if (!ret && opcode[1]==3) {} else {printf("Autotest %03d ERROR (proximity labels)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing proximity labels OK\n"); + + ret=RasmAssemble(AUTOTEST_STRUCT,strlen(AUTOTEST_STRUCT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (structs)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing structs OK\n"); + + ret=RasmAssemble(AUTOTEST_STRUCT2,strlen(AUTOTEST_STRUCT2),&opcode,&opcodelen); + if (!ret && opcodelen==1) {} else {printf("Autotest %03d ERROR (sizeof struct fields)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing SIZEOF struct fields OK\n"); + + ret=RasmAssemble(AUTOTEST_REPEAT,strlen(AUTOTEST_REPEAT),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (extended repeat)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing REPEAT cases OK\n"); + + ret=RasmAssemble(AUTOTEST_REPEATKO,strlen(AUTOTEST_REPEATKO),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (repeat without end must return error)\n",cpt);exit(-1);} +printf("testing REPEAT without REND OK\n"); + + ret=RasmAssemble(AUTOTEST_WHILEKO,strlen(AUTOTEST_WHILEKO),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (while without end must return error)\n",cpt);exit(-1);} +printf("testing WHILE without WEND OK\n"); + + ret=RasmAssemble(AUTOTEST_TICKER,strlen(AUTOTEST_TICKER),&opcode,&opcodelen); + if (!ret && opcodelen==18) {} else {printf("Autotest %03d ERROR (ticker (re)count)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing ticker OK\n"); + + ret=RasmAssemble(AUTOTEST_DEFUSED,strlen(AUTOTEST_DEFUSED),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (ifdef ifused)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing IFDEF / IFUSED OK\n"); + + ret=RasmAssemble(AUTOTEST_SAVEINVALID1,strlen(AUTOTEST_SAVEINVALID1),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (invalid size for SAVE)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing invalid size for SAVE OK\n"); + + ret=RasmAssemble(AUTOTEST_SAVEINVALID2,strlen(AUTOTEST_SAVEINVALID2),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (invalid offset for SAVE)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing invalid offset (too low) for SAVE OK\n"); + + ret=RasmAssemble(AUTOTEST_SAVEINVALID3,strlen(AUTOTEST_SAVEINVALID3),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (invalid offset for SAVE)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing invalid offset (too high) for SAVE OK\n"); + + ret=RasmAssemble(AUTOTEST_INHIBITION2,strlen(AUTOTEST_INHIBITION2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (if switch inhibition)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing if/switch inhibition OK\n"); + + ret=RasmAssemble(AUTOTEST_INHIBITIONMAX,strlen(AUTOTEST_INHIBITIONMAX),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (moar inhibition)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing more inhibition cases OK\n"); + + ret=RasmAssemble(AUTOTEST_MACROPROX,strlen(AUTOTEST_MACROPROX),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (macro + prox)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing regression case with proximity label following macro definition OK\n"); + + ret=RasmAssemble(AUTOTEST_PROXBACK,strlen(AUTOTEST_PROXBACK),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (boucle/macro + prox = recup global)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing global label back as reference when leaving macro and loops OK\n"); + + ret=RasmAssemble(AUTOTEST_LOCAPROX,strlen(AUTOTEST_LOCAPROX),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (far local+prox access)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing far access of a proximity label refering to local OK\n"); + + ret=RasmAssemble(AUTOTEST_NEGATIVE,strlen(AUTOTEST_NEGATIVE),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula case 0)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula case 0 OK\n"); + + ret=RasmAssemble(AUTOTEST_FORMULA1,strlen(AUTOTEST_FORMULA1),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula case 1)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula case 1 OK\n"); + + ret=RasmAssemble(AUTOTEST_SETINSIDE,strlen(AUTOTEST_SETINSIDE),&opcode,&opcodelen); + if (ret) {} else {printf("Autotest %03d ERROR (set var inside expression must trigger error)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing var set inside an expression must trigger an error OK\n"); + + ret=RasmAssemble(AUTOTEST_CODESKIP,strlen(AUTOTEST_CODESKIP),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (code skip)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing code skip OK\n"); + + ret=RasmAssemble(AUTOTEST_FORMULA2,strlen(AUTOTEST_FORMULA2),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula case 2 function+multiple parenthesis)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula functions + multiple parenthesis OK\n"); + + ret=RasmAssemble(AUTOTEST_PLUSCOLOR,strlen(AUTOTEST_PLUSCOLOR),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula func for Plus color management)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula function for Plus color management OK\n"); + + ret=RasmAssemble(AUTOTEST_FRAC,strlen(AUTOTEST_FRAC),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (formula func FRAC)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing formula FRAC function OK\n"); + + ret=RasmAssemble(AUTOTEST_UNDERVAR,strlen(AUTOTEST_UNDERVAR),&opcode,&opcodelen); + if (!ret && opcodelen==4) {} else {printf("Autotest %03d ERROR (var starting with _)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing var names starting with '_' OK\n"); + + ret=RasmAssemble(AUTOTEST_NOEXPORT,strlen(AUTOTEST_NOEXPORT),&opcode,&opcodelen); + if (!ret && opcodelen==2) {} else {printf("Autotest %03d ERROR (noexport/enoexport)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing export/noexport OK\n"); + + ret=RasmAssemble(AUTOTEST_ENHANCED_LD,strlen(AUTOTEST_ENHANCED_LD),&opcode,&opcodelen); + if (!ret && memcmp(opcode,opcode+opcodelen/2,opcodelen/2)==0) {} else {printf("Autotest %03d ERROR (enhanced LD)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing enhanced LD OK\n"); + + ret=RasmAssemble(AUTOTEST_ENHANCED_LD2,strlen(AUTOTEST_ENHANCED_LD2),&opcode,&opcodelen); + if (!ret && memcmp(opcode,opcode+opcodelen/2,opcodelen/2)==0) {} else {printf("Autotest %03d ERROR (enhanced LD 2)\n",cpt);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing enhanced LD variante OK\n"); + + ret=RasmAssemble(AUTOTEST_ENHANCED_PUSHPOP,strlen(AUTOTEST_ENHANCED_PUSHPOP),&opcode,&opcodelen); + if (!ret && memcmp(opcode,opcode+opcodelen/2,opcodelen/2)==0) {} else {printf("Autotest %03d ERROR (enhanced PUSH/POP/NOP)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing enhanced PUSH/POP OK\n"); + + ret=RasmAssemble(AUTOTEST_PAGELABELGEN,strlen(AUTOTEST_PAGELABELGEN),&opcode,&opcodelen); + if (!ret) {} else {printf("Autotest %03d ERROR (pagelabelgen)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing page tag with generated label name OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_EMBEDDED_ERRORS,strlen(AUTOTEST_EMBEDDED_ERRORS),&opcode,&opcodelen,&debug); + if (ret && debug->nberror==2 && debug->nbsymbol==3) { +/* + printf("\n"); + for (i=0;i<debug->nberror;i++) { + printf("%d -> %s\n",i,debug->error[i].msg); + } + for (i=0;i<debug->nbsymbol;i++) { + printf("%d -> %s=%d\n",i,debug->symbol[i].name,debug->symbol[i].v); + } + RasmFreeInfoStruct(debug); +*/ + } else {printf("Autotest %03d ERROR (embedded error struct) err=%d nberr=%d (2) nbsymb=%d (3)\n",cpt,ret,debug->nberror,debug->nbsymbol);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing internal error struct OK\n"); + + ret=RasmAssembleInfo(AUTOTEST_EMBEDDED_LABELS,strlen(AUTOTEST_EMBEDDED_LABELS),&opcode,&opcodelen,&debug); + if (!ret && debug->nbsymbol==3) { + /* + printf("\nnbsymbol=%d\n",debug->nbsymbol); + for (i=0;i<debug->nbsymbol;i++) { + printf("%d -> %s=%d\n",i,debug->symbol[i].name,debug->symbol[i].v); + }*/ + RasmFreeInfoStruct(debug); + } else {printf("Autotest %03d ERROR (embedded test)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; +printf("testing internal label struct OK\n"); + +#ifdef RDD + printf("\n%d bytes\n",_static_library_memory_used); + + tmpstr3=FileReadContent("./test/PlayerAky.asm",&filelen); + printf(".");fflush(stdout);ret=RasmAssembleInfo(tmpstr3,filelen,&opcode,&opcodelen,&debug); + if (!ret) {} else {printf("Autotest %03d ERROR (PlayerAky)\n",cpt);MiniDump(opcode,opcodelen);exit(-1);} + if (opcode) MemFree(opcode);opcode=NULL;cpt++; + RasmFreeInfoStruct(debug); + MemFree(tmpstr3); + + printf("\n%d bytes\n",_static_library_memory_used); +#endif + + FileRemoveIfExists("rasmoutput.cpr"); + + printf("All internal tests OK\n"); + #ifdef RDD + /* private dev lib tools */ +printf("checking memory\n"); + CloseLibrary(); + #endif + exit(0); +} + + +/****************************************************** +LZ48 v005 / LZ49 v002 +******************************************************/ +int LZ48_encode_extended_length(unsigned char *odata, int length) +{ + int ioutput=0; + + while (length>=255) { + odata[ioutput++]=0xFF; + length-=255; + } + /* if the last value is 255 we must encode 0 to end extended length */ + /*if (length==0) rasm_printf(ae,"bugfixed!\n");*/ + odata[ioutput++]=(unsigned char)length; + return ioutput; +} + +int LZ48_encode_block(unsigned char *odata,unsigned char *data, int literaloffset,int literalcpt,int offset,int maxlength) +{ + int ioutput=1; + int token=0; + int i; + + if (offset<0 || offset>255) { + fprintf(stderr,"internal offset error!\n"); + exit(-2); + } + + if (literalcpt<15) { + token=literalcpt<<4; + } else { + token=0xF0; + ioutput+=LZ48_encode_extended_length(odata+ioutput,literalcpt-15); + } + + for (i=0;i<literalcpt;i++) odata[ioutput++]=data[literaloffset++]; + + if (maxlength<18) { + if (maxlength>2) { + token|=(maxlength-3); + } else { + /* endoffset has no length */ + } + } else { + token|=0xF; + ioutput+=LZ48_encode_extended_length(odata+ioutput,maxlength-18); + } + + odata[ioutput++]=(unsigned char)offset-1; + + odata[0]=(unsigned char)token; + return ioutput; +} + +unsigned char *LZ48_encode_legacy(unsigned char *data, int length, int *retlength) +{ + int i,startscan,current=1,token,ioutput=1,curscan; + int maxoffset=0,maxlength,matchlength,literal=0,literaloffset=1; + unsigned char *odata=NULL; + + odata=MemMalloc((size_t)length*1.5+10); + if (!odata) { + fprintf(stderr,"malloc(%.0lf) - memory full\n",(size_t)length*1.5+10); + exit(-1); + } + + /* first byte always literal */ + odata[0]=data[0]; + + /* force short data encoding */ + if (length<5) { + token=(length-1)<<4; + odata[ioutput++]=(unsigned char)token; + for (i=1;i<length;i++) odata[ioutput++]=data[current++]; + odata[ioutput++]=0xFF; + *retlength=ioutput; + return odata; + } + + while (current<length) { + maxlength=0; + startscan=current-255; + if (startscan<0) startscan=0; + while (startscan<current) { + matchlength=0; + curscan=current; + for (i=startscan;curscan<length;i++) { + if (data[i]==data[curscan++]) matchlength++; else break; + } + if (matchlength>=3 && matchlength>maxlength) { + maxoffset=startscan; + maxlength=matchlength; + } + startscan++; + } + if (maxlength) { + ioutput+=LZ48_encode_block(odata+ioutput,data,literaloffset,literal,current-maxoffset,maxlength); + current+=maxlength; + literaloffset=current; + literal=0; + } else { + literal++; + current++; + } + } + ioutput+=LZ48_encode_block(odata+ioutput,data,literaloffset,literal,0,0); + *retlength=ioutput; + return odata; +} + +int LZ49_encode_extended_length(unsigned char *odata, int length) +{ + int ioutput=0; + + while (length>=255) { + odata[ioutput++]=0xFF; + length-=255; + } + /* if the last value is 255 we must encode 0 to end extended length */ + /*if (length==0) rasm_printf(ae,"bugfixed!\n");*/ + odata[ioutput++]=(unsigned char)length; + return ioutput; +} + +int LZ49_encode_block(unsigned char *odata,unsigned char *data, int literaloffset,int literalcpt,int offset,int maxlength) +{ + int ioutput=1; + int token=0; + int i; + + if (offset<0 || offset>511) { + fprintf(stderr,"internal offset error!\n"); + exit(-2); + } + + if (literalcpt<7) { + token=literalcpt<<4; + } else { + token=0x70; + ioutput+=LZ49_encode_extended_length(odata+ioutput,literalcpt-7); + } + + for (i=0;i<literalcpt;i++) odata[ioutput++]=data[literaloffset++]; + + if (maxlength<18) { + if (maxlength>2) { + token|=(maxlength-3); + } else { + /* endoffset has no length */ + } + } else { + token|=0xF; + ioutput+=LZ49_encode_extended_length(odata+ioutput,maxlength-18); + } + + if (offset>255) { + token|=0x80; + offset-=256; + } + odata[ioutput++]=(unsigned char)offset-1; + + odata[0]=(unsigned char)token; + return ioutput; +} + +unsigned char *LZ49_encode_legacy(unsigned char *data, int length, int *retlength) +{ + int i,startscan,current=1,token,ioutput=1,curscan; + int maxoffset=0,maxlength,matchlength,literal=0,literaloffset=1; + unsigned char *odata=NULL; + + odata=MemMalloc((size_t)(length*1.5+10)); + if (!odata) { + fprintf(stderr,"malloc(%.0lf) - memory full\n",(size_t)length*1.5+10); + exit(-1); + } + + /* first byte always literal */ + odata[0]=data[0]; + + /* force short data encoding */ + if (length<5) { + token=(length-1)<<4; + odata[ioutput++]=(unsigned char)token; + for (i=1;i<length;i++) odata[ioutput++]=data[current++]; + odata[ioutput++]=0xFF; + *retlength=ioutput; + return odata; + } + + while (current<length) { + maxlength=0; + startscan=current-511; + if (startscan<0) startscan=0; + while (startscan<current) { + matchlength=0; + curscan=current; + for (i=startscan;curscan<length;i++) { + if (data[i]==data[curscan++]) matchlength++; else break; + } + if (matchlength>=3 && matchlength>maxlength) { + maxoffset=startscan; + maxlength=matchlength; + } + startscan++; + } + if (maxlength) { + ioutput+=LZ49_encode_block(odata+ioutput,data,literaloffset,literal,current-maxoffset,maxlength); + current+=maxlength; + literaloffset=current; + literal=0; + } else { + literal++; + current++; + } + } + ioutput+=LZ49_encode_block(odata+ioutput,data,literaloffset,literal,0,0); + *retlength=ioutput; + return odata; +} + + +/*************************************** + semi-generic body of program +***************************************/ + +#ifndef INTEGRATED_ASSEMBLY + +/* + Usage + display the mandatory parameters +*/ +void Usage(int help) +{ + #undef FUNC + #define FUNC "Usage" + + printf("%s (c) 2017 Edouard BERGE (use -n option to display all licenses)\n",RASM_VERSION); + #ifndef NO_3RD_PARTIES + printf("LZ4 (c) Yann Collet / ZX7 (c) Einar Saukas / Exomizer 2 (c) Magnus Lind\n"); + #endif + printf("\n"); + printf("SYNTAX: rasm <inputfile> [options]\n"); + printf("\n"); + + if (help) { + printf("FILENAMES:\n"); + printf("-oa automatic radix from input filename\n"); + printf("-o <outputfile radix> choose a common radix for all files\n"); + printf("-ob <binary filename> choose a full filename for binary output\n"); + printf("-oc <cartridge filename> choose a full filename for cartridge output\n"); + printf("-oi <snapshot filename> choose a full filename for snapshot output\n"); + printf("-os <symbol filename> choose a full filename for symbol output\n"); + printf("-ot <tape filename> choose a full filename for tape output\n"); + printf("-ok <breakpoint filename>choose a full filename for breakpoint output\n"); + printf("-I<path> set a path for files to read\n"); + printf("-no disable all file output\n"); + printf("DEPENDENCIES EXPORT:\n"); + printf("-depend=make output dependencies on a single line\n"); + printf("-depend=list output dependencies as a list\n"); + printf("if 'binary filename' is set then it will be outputed first\n"); + printf("SYMBOLS EXPORT:\n"); + printf("-s export symbols %%s #%%X B%%d (label,adr,cprbank)\n"); + printf("-sz export symbols with ZX emulator convention\n"); + printf("-sp export symbols with Pasmo convention\n"); + printf("-sw export symbols with Winape convention\n"); + printf("-ss export symbols in the snapshot (SYMB chunk for ACE)\n"); + printf("-sc <format> export symbols with source code convention\n"); + printf("-sm export symbol in multiple files (one per bank)\n"); + printf("-l <labelfile> import symbol file (winape,pasmo,rasm)\n"); + printf("-eb export breakpoints\n"); + printf("-wu warn for unused symbols (alias, var or label)\n"); + printf("SYMBOLS ADDITIONAL OPTIONS:\n"); + printf("-sl export also local symbol\n"); + printf("-sv export also variables symbol\n"); + printf("-sq export also EQU symbol\n"); + printf("-sa export all symbols (like -sl -sv -sq option)\n"); + printf("-Dvariable=value import value for variable\n"); + printf("COMPATIBILITY:\n"); + printf("-m Maxam style calculations\n"); + printf("-dams Dams 'dot' label convention\n"); + printf("-ass AS80 behaviour mimic\n"); + printf("-uz UZ80 behaviour mimic\n"); + + printf("EDSK generation/update:\n"); + printf("-eo overwrite files on disk if it already exists\n"); + printf("SNAPSHOT:\n"); + printf("-sb export breakpoints in snapshot (BRKS & BRKC chunks)\n"); + printf("-ss export symbols in the snapshot (SYMB chunk for ACE)\n"); + printf("-v2 export snapshot version 2 instead of version 3\n"); + printf("PARSING:\n"); + printf("-me <value> set maximum number of error (0 means no limit)\n"); + printf("-xr extended error display\n"); + printf("-w disable warnings\n"); + printf("-void force void usage with macro without parameter\n"); + printf("\n"); + } else { + printf("use option -h for help\n"); + printf("\n"); + } + + exit(ABORT_ERROR); +} + +void Licenses() +{ + #undef FUNC + #define FUNC "Licenses" + +printf(" ____ \n"); +printf(" | _ \\ __ _ ___ _ __ ___ \n"); +printf(" | |_) / _` / __| '_ ` _ \\ \n"); +printf(" | _ < (_| \\__ \\ | | | | |\n"); +printf(" |_| \\_\\__,_|___/_| |_| |_|\n"); +printf("\n"); +printf(" is using MIT 'expat' license\n"); +printf("\" Copyright (c) BERGE Edouard (roudoudou)\n\n"); + +printf("Permission is hereby granted, free of charge,\n"); +printf("to any person obtaining a copy of this software\n"); +printf("and associated documentation/source files of\n"); +printf("RASM, to deal in the Software without restriction,\n"); +printf("including without limitation the rights to use,\n"); +printf("copy, modify, merge, publish, distribute,\n"); +printf("sublicense, and/or sell copies of the Software,\n"); +printf("and to permit persons to whom the Software is\n"); +printf("furnished to do so, subject to the following\n"); +printf("conditions:\n"); + +printf("The above copyright notice and this permission\n"); +printf("notice shall be included in all copies or\n"); +printf("substantial portions of the Software.\n"); +printf("The Software is provided 'as is', without\n"); +printf("warranty of any kind, express or implied,\n"); +printf("including but not limited to the warranties of\n"); +printf("merchantability, fitness for a particular\n"); +printf("purpose and noninfringement. In no event shall\n"); +printf("the authors or copyright holders be liable for\n"); +printf("any claim, damages or other liability, whether\n"); +printf("in an action of contract, tort or otherwise,\n"); +printf("arising from, out of or in connection with the\n"); +printf("software or the use or other dealings in the\n"); +printf("Software. \"\n"); + +#ifndef NO_3RD_PARTIES +printf("\n\n\n\n"); +printf("******* license of LZ4 cruncher / sources were modified ***********\n\n\n\n"); + +printf("BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n"); + +printf("Redistribution and use in source and binary forms, with or without\n"); +printf("modification, are permitted provided that the following conditions are\n"); +printf("met:\n\n"); + +printf(" * Redistributions of source code must retain the above copyright\n"); +printf("notice, this list of conditions and the following disclaimer.\n"); +printf(" * Redistributions in binary form must reproduce the above\n"); +printf("copyright notice, this list of conditions and the following disclaimer\n"); +printf("in the documentation and/or other materials provided with the\n"); +printf("distribution.\n\n"); + +printf("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"); +printf("'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"); +printf("LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"); +printf("A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"); +printf("OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"); +printf("SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"); +printf("LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"); +printf("DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"); +printf("THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"); +printf("(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"); +printf("OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"); + +printf("You can contact the author at :\n"); +printf(" - LZ4 homepage : http://www.lz4.org\n"); +printf(" - LZ4 source repository : https://github.com/lz4/lz4\n"); + + +printf("\n\n\n\n"); +printf("******* license of ZX7 cruncher / sources were modified ***********\n\n\n\n"); + + +printf(" * (c) Copyright 2012 by Einar Saukas. All rights reserved.\n"); +printf(" *\n"); +printf(" * Redistribution and use in source and binary forms, with or without\n"); +printf(" * modification, are permitted provided that the following conditions are met:\n"); +printf(" * * Redistributions of source code must retain the above copyright\n"); +printf(" * notice, this list of conditions and the following disclaimer.\n"); +printf(" * * Redistributions in binary form must reproduce the above copyright\n"); +printf(" * notice, this list of conditions and the following disclaimer in the\n"); +printf(" * documentation and/or other materials provided with the distribution.\n"); +printf(" * * The name of its author may not be used to endorse or promote products\n"); +printf(" * derived from this software without specific prior written permission.\n"); +printf(" *\n"); +printf(" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND\n"); +printf(" * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"); +printf(" * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"); +printf(" * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\n"); +printf(" * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"); +printf(" * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"); +printf(" * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n"); +printf(" * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"); +printf(" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"); +printf(" * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"); + + +printf("\n\n\n\n"); +printf("******* license of exomizer cruncher / sources were modified ***********\n\n\n\n"); + + +printf(" * Copyright (c) 2005 Magnus Lind.\n"); +printf(" *\n"); +printf(" * This software is provided 'as-is', without any express or implied warranty.\n"); +printf(" * In no event will the authors be held liable for any damages arising from\n"); +printf(" * the use of this software.\n"); +printf(" *\n"); +printf(" * Permission is granted to anyone to use this software, alter it and re-\n"); +printf(" * distribute it freely for any non-commercial, non-profit purpose subject to\n"); +printf(" * the following restrictions:\n"); +printf(" *\n"); +printf(" * 1. The origin of this software must not be misrepresented; you must not\n"); +printf(" * claim that you wrote the original software. If you use this software in a\n"); +printf(" * product, an acknowledgment in the product documentation would be\n"); +printf(" * appreciated but is not required.\n"); +printf(" *\n"); +printf(" * 2. Altered source versions must be plainly marked as such, and must not\n"); +printf(" * be misrepresented as being the original software.\n"); +printf(" *\n"); +printf(" * 3. This notice may not be removed or altered from any distribution.\n"); +printf(" *\n"); +printf(" * 4. The names of this software and/or it's copyright holders may not be\n"); +printf(" * used to endorse or promote products derived from this software without\n"); +printf(" * specific prior written permission.\n"); +#endif + +printf("\n\n"); + + + + exit(0); +} + +int _internal_check_flexible(char *fxp) { + #undef FUNC + #define FUNC "_internal_check_flexible" + + char *posval,*posvar; + int cpt=0,i; + + posvar=strstr(fxp,"%s"); + posval=strstr(fxp,"%"); + if (!posval || !posvar) { + printf("invalid flexible export string, need 2 formated fields, example: \"%%s %%d\"\n"); + exit(1); + } + if (posval<posvar) { + printf("invalid flexible export string, must be %%s before the %% for value, example: \"%%s %%d\"\n"); + exit(1); + } + for (i=0;fxp[i];i++) if (fxp[i]=='%') cpt++; + if (cpt>2) { + printf("invalid flexible export string, must be only two formated fields, example: \"%%s %%d\"\n"); + exit(1); + } + + return 1; +} +/* + ParseOptions + + used to parse command line and configuration file +*/ +int ParseOptions(char **argv,int argc, struct s_parameter *param) +{ + #undef FUNC + #define FUNC "ParseOptions" + + char *sep; + int i=0; + + if (strcmp(argv[i],"-autotest")==0) { + RasmAutotest(); + } else if (strcmp(argv[i],"-uz")==0) { + param->as80=2; + } else if (strcmp(argv[i],"-ass")==0) { + param->as80=1; + } else if (strcmp(argv[i],"-eb")==0) { + param->export_brk=1; + } else if (strcmp(argv[i],"-wu")==0) { + param->warn_unused=1; + } else if (strcmp(argv[i],"-dams")==0) { + } else if (strcmp(argv[i],"-void")==0) { + param->macrovoid=1; + } else if (strcmp(argv[i],"-xr")==0) { + param->extended_error=1; + } else if (strcmp(argv[i],"-eo")==0) { + param->edskoverwrite=1; + } else if (strcmp(argv[i],"-depend=make")==0) { + param->dependencies=E_DEPENDENCIES_MAKE; + param->checkmode=1; + } else if (strcmp(argv[i],"-depend=list")==0) { + param->dependencies=E_DEPENDENCIES_LIST; + param->checkmode=1; + } else if (strcmp(argv[i],"-no")==0) { + param->checkmode=1; + } else if (strcmp(argv[i],"-w")==0) { + param->nowarning=1; + } else if (argv[i][0]=='-') { + switch(argv[i][1]) + { + case 'I': + if (argv[i][2]) { + char *curpath; + int l; + l=strlen(argv[i]); + curpath=MemMalloc(l); /* strlen(path)+2 */ + strcpy(curpath,argv[i]+2); +#ifdef OS_WIN + if (argv[i][l-1]!='/' && argv[i][l-1]!='\\') strcat(curpath,"\\"); +#else + if (argv[i][l-1]!='/' && argv[i][l-1]!='\\') strcat(curpath,"/"); +#endif + FieldArrayAddDynamicValueConcat(¶m->pathdef,¶m->npath,¶m->mpath,curpath); + MemFree(curpath); + } else { + Usage(1); + } + break; + case 'D': + if ((sep=strchr(argv[i],'='))!=NULL) { + if (sep!=argv[i]+2) { + FieldArrayAddDynamicValueConcat(¶m->symboldef,¶m->nsymb,¶m->msymb,argv[i]+2); + } else { + Usage(1); + } + } else { + Usage(1); + } + break; + case 'm': + switch (argv[i][2]) { + case 0: + param->rough=0.0; + return i; + case 'e': + if (argv[i][3]) Usage(1); + if (i+1<argc) { + param->maxerr=atoi(argv[++i]); + return i; + } + default:Usage(1); + } + Usage(1); + break; + case 's': + if (argv[i][2] && argv[i][3]) Usage(1); + switch (argv[i][2]) { + case 0:param->export_sym=1;return 0; + case 'z': + param->export_sym=5;return 0; + case 'm': + param->export_multisym=1;return 0; + case 'b': + param->export_snabrk=1;return 0; + case 'p': + param->export_sym=2;return 0; + case 'w': + param->export_sym=3;return 0; + case 'c': + if (i+1<argc) { + param->export_sym=4; + param->flexible_export=TxtStrDup(argv[++i]); + param->flexible_export=MemRealloc(param->flexible_export,strlen(param->flexible_export)+3); + strcat(param->flexible_export,"\n"); + /* check export string */ + if (_internal_check_flexible(param->flexible_export)) return i; else Usage(1); + } + Usage(1); + case 'l': + param->export_local=1;return 0; + case 'v': + param->export_var=1;return 0; + case 'q': + param->export_equ=1;return 0; + case 'a': + param->export_local=1; + param->export_var=1; + param->export_equ=1; + return 0; + case 's': + param->export_local=1; + param->export_sym=1; + param->export_sna=1;return 0; + default: + break; + } + Usage(1); + case 'l': + if (argv[i][2]) Usage(1); + if (i+1<argc) { + FieldArrayAddDynamicValue(¶m->labelfilename,argv[++i]); + break; + } + Usage(1); + case 'i': +printf("@@@\n@@@ --> deprecated option, there is no need to use -i option to set input file <--\n@@@\n"); + Usage(0); + case 'o': + if (argv[i][2] && argv[i][3]) Usage(1); + switch (argv[i][2]) { + case 0: + if (i+1<argc && param->outputfilename==NULL) { + param->outputfilename=argv[++i]; + break; + } + Usage(1); + case 'a': + param->automatic_radix=1; + break; + case 't': + if (i+1<argc && param->tape_name==NULL) { + param->tape_name=argv[++i]; + break; + } + Usage(1); + case 'i': + if (i+1<argc && param->snapshot_name==NULL) { + param->snapshot_name=argv[++i]; + break; + } + Usage(1); + case 'b': + if (i+1<argc && param->binary_name==NULL) { + param->binary_name=argv[++i]; + break; + } + Usage(1); + case 'c': + if (i+1<argc && param->cartridge_name==NULL) { + param->cartridge_name=argv[++i]; + break; + } + Usage(1); + case 'k': + if (i+1<argc && param->breakpoint_name==NULL) { + param->breakpoint_name=argv[++i]; + break; + } + Usage(1); + case 's': + if (i+1<argc && param->symbol_name==NULL) { + param->symbol_name=argv[++i]; + break; + } + Usage(1); + default: + Usage(1); + } + break; + case 'd':if (!argv[i][2]) printf("deprecated option -d\n"); else Usage(1); + break; + case 'a':if (!argv[i][2]) printf("deprecated option -a\n"); else Usage(1); + break; + case 'c':if (!argv[i][2]) printf("deprecated option -c\n"); else Usage(1); + break; + case 'v': + if (!argv[i][2]) { + printf("deprecated option -v\n"); + } else if (argv[i][2]=='2') { + param->v2=1; + } + break; + case 'n':if (!argv[i][2]) Licenses(); else Usage(1); + case 'h':Usage(1); + default: + Usage(1); + } + } else { + if (param->filename==NULL) { + param->filename=TxtStrDup(argv[i]); + } else if (param->outputfilename==NULL) { + param->outputfilename=argv[i]; + } else Usage(1); + } + return i; +} + +/* + GetParametersFromCommandLine + retrieve parameters from command line and fill pointers to file names +*/ +void GetParametersFromCommandLine(int argc, char **argv, struct s_parameter *param) +{ + #undef FUNC + #define FUNC "GetParametersFromCommandLine" + int i; + + for (i=1;i<argc;i++) + i+=ParseOptions(&argv[i],argc-i,param); + + if (!param->filename) Usage(0); + if (param->export_local && !param->export_sym) Usage(1); // à revoir? +} + +/* + main + + check parameters + execute the main processing +*/ + + +int main(int argc, char **argv) +{ + #undef FUNC + #define FUNC "main" + + struct s_parameter param={0}; + int ret; + + param.maxerr=20; + param.rough=0.5; + + GetParametersFromCommandLine(argc,argv,¶m); + ret=Rasm(¶m); + #ifdef RDD + /* private dev lib tools */ +printf("checking memory\n"); + CloseLibrary(); + #endif + exit(ret); + return 0; // Open WATCOM Warns without this... +} + +#endif + + diff --git a/tools/rasm_src/zx7.h b/tools/rasm_src/zx7.h new file mode 100644 index 0000000..f03659d --- /dev/null +++ b/tools/rasm_src/zx7.h @@ -0,0 +1,293 @@ +/*
+
+Warning! This is a modified version of original sources!
+
+To sum up:
+- all include files and C sources were merged in a single file
+- existing logs were removed (except error logs)
+- main were removed and wrapper added
+
+
+ * (c) Copyright 2012 by Einar Saukas. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The name of its author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define ZX7_MAX_OFFSET 2176 /* range 1..2176 */
+#define ZX7_MAX_LEN 65536 /* range 2..65536 */
+
+typedef struct match_t {
+ size_t index;
+ struct match_t *next;
+} Match;
+
+typedef struct optimal_t {
+ size_t bits;
+ int offset;
+ int len;
+} Optimal;
+
+Optimal *optimize(unsigned char *input_data, size_t input_size);
+
+unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, size_t input_size, size_t *output_size);
+
+/*
+ * (c) Copyright 2012 by Einar Saukas. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The name of its author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+int elias_gamma_bits(int value) {
+ int bits;
+
+ bits = 1;
+ while (value > 1) {
+ bits += 2;
+ value >>= 1;
+ }
+ return bits;
+}
+
+int count_bits(int offset, int len) {
+ return 1 + (offset > 128 ? 12 : 8) + elias_gamma_bits(len-1);
+}
+
+Optimal* optimize(unsigned char *input_data, size_t input_size) {
+ size_t *min;
+ size_t *max;
+ Match *matches;
+ Match *match_slots;
+ Optimal *optimal;
+ Match *match;
+ int match_index;
+ int offset;
+ size_t len;
+ size_t best_len;
+ size_t bits;
+ size_t i;
+
+ /* allocate all data structures at once */
+ min = (size_t *)calloc(ZX7_MAX_OFFSET+1, sizeof(size_t));
+ max = (size_t *)calloc(ZX7_MAX_OFFSET+1, sizeof(size_t));
+ matches = (Match *)calloc(256*256, sizeof(Match));
+ match_slots = (Match *)calloc(input_size, sizeof(Match));
+ optimal = (Optimal *)calloc(input_size, sizeof(Optimal));
+
+ if (!min || !max || !matches || !match_slots || !optimal) {
+ fprintf(stderr, "Error: Insufficient memory\n");
+ exit(1);
+ }
+
+ /* first byte is always literal */
+ optimal[0].bits = 8;
+
+ /* process remaining bytes */
+ for (i = 1; i < input_size; i++) {
+
+ optimal[i].bits = optimal[i-1].bits + 9;
+ match_index = input_data[i-1] << 8 | input_data[i];
+ best_len = 1;
+ for (match = &matches[match_index]; match->next != NULL && best_len < ZX7_MAX_LEN; match = match->next) {
+ offset = i - match->next->index;
+ if (offset > ZX7_MAX_OFFSET) {
+ match->next = NULL;
+ break;
+ }
+
+ for (len = 2; len <= ZX7_MAX_LEN; len++) {
+ if (len > best_len) {
+ best_len = len;
+ bits = optimal[i-len].bits + count_bits(offset, len);
+ if (optimal[i].bits > bits) {
+ optimal[i].bits = bits;
+ optimal[i].offset = offset;
+ optimal[i].len = len;
+ }
+ } else if (i+1 == max[offset]+len && max[offset] != 0) {
+ len = i-min[offset];
+ if (len > best_len) {
+ len = best_len;
+ }
+ }
+ if (i < offset+len || input_data[i-len] != input_data[i-len-offset]) {
+ break;
+ }
+ }
+ min[offset] = i+1-len;
+ max[offset] = i;
+ }
+ match_slots[i].index = i;
+ match_slots[i].next = matches[match_index].next;
+ matches[match_index].next = &match_slots[i];
+ }
+
+ /* save time by releasing the largest block only, the O.S. will clean everything else later */
+ free(match_slots);
+
+ return optimal;
+}
+
+/*
+ * (c) Copyright 2012 by Einar Saukas. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * The name of its author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+unsigned char* output_data;
+size_t output_index;
+size_t bit_index;
+int bit_mask;
+
+void write_byte(int value) {
+ output_data[output_index++] = value;
+}
+
+void write_bit(int value) {
+ if (bit_mask == 0) {
+ bit_mask = 128;
+ bit_index = output_index;
+ write_byte(0);
+ }
+ if (value > 0) {
+ output_data[bit_index] |= bit_mask;
+ }
+ bit_mask >>= 1;
+}
+
+void write_elias_gamma(int value) {
+ int i;
+
+ for (i = 2; i <= value; i <<= 1) {
+ write_bit(0);
+ }
+ while ((i >>= 1) > 0) {
+ write_bit(value & i);
+ }
+}
+
+unsigned char *ZX7_compress(Optimal *optimal, unsigned char *input_data, size_t input_size, size_t *output_size) {
+ size_t input_index;
+ size_t input_prev;
+ int offset1;
+ int mask;
+ int i;
+
+ /* calculate and allocate output buffer */
+ input_index = input_size-1;
+ *output_size = (optimal[input_index].bits+18+7)/8;
+ output_data = (unsigned char *)MemMalloc(*output_size);
+
+ /* un-reverse optimal sequence */
+ optimal[input_index].bits = 0;
+ while (input_index > 0) {
+ input_prev = input_index - (optimal[input_index].len > 0 ? optimal[input_index].len : 1);
+ optimal[input_prev].bits = input_index;
+ input_index = input_prev;
+ }
+
+ output_index = 0;
+ bit_mask = 0;
+
+ /* first byte is always literal */
+ write_byte(input_data[0]);
+
+ /* process remaining bytes */
+ while ((input_index = optimal[input_index].bits) > 0) {
+ if (optimal[input_index].len == 0) {
+
+ /* literal indicator */
+ write_bit(0);
+
+ /* literal value */
+ write_byte(input_data[input_index]);
+
+ } else {
+
+ /* sequence indicator */
+ write_bit(1);
+
+ /* sequence length */
+ write_elias_gamma(optimal[input_index].len-1);
+
+ /* sequence offset */
+ offset1 = optimal[input_index].offset-1;
+ if (offset1 < 128) {
+ write_byte(offset1);
+ } else {
+ offset1 -= 128;
+ write_byte((offset1 & 127) | 128);
+ for (mask = 1024; mask > 127; mask >>= 1) {
+ write_bit(offset1 & mask);
+ }
+ }
+ }
+ }
+
+ /* sequence indicator */
+ write_bit(1);
+
+ /* end marker > MAX_LEN */
+ for (i = 0; i < 16; i++) {
+ write_bit(0);
+ }
+ write_bit(1);
+
+ return output_data;
+}
|