-- (c) Copyright - See License.txt
--
-- mini Euphoria front-end for stand-alone back-end
-- we redundantly declare some things to keep the size down

with define BACKEND

ifdef ETYPE_CHECK then
	with type_check
elsedef
	without type_check
end ifdef

include mode.e
set_mode("backend", 0 )

include std/machine.e
include std/wildcard.e
include std/os.e
include std/io.e
include std/sequence.e
include std/text.e
include std/console.e
include std/search.e
include std/filesys.e

include global.e
include common.e
include reswords.e
include compress.e
include cominit.e
include pathopen.e
include preproc.e
include msgtext.e
include intinit.e

sequence misc
integer il_file = 0

include backend.e

procedure fatal(sequence msg)
-- fatal error 
    puts(2, msg)
    puts(2, '\n')
    maybe_any_key( GetMsgText(277, 0) )
	abort(1)
end procedure

procedure verify_checksum(atom size, atom vchecksum)
-- check that the IL was generated by our binder, 
-- and has not been tampered with   
	atom checksum
	integer prev_c, c
	
	checksum = 11352 -- magic starting point
	size = 0
	prev_c = -1
	-- read whole IL
	while 1 do
		c = getc(current_db)
		if c = -1 then
			exit
		end if
		
		if c < 100 then
			if c != 'A' then
				checksum += c
			end if
		else
			checksum += c*2
		end if
		size -= 1
		if size = 0 then
			exit
		end if
		prev_c = c
	end while
	
	checksum = remainder(checksum, 1000000000)
	if checksum != vchecksum then
		fatal( GetMsgText(295) )
	end if
end procedure   

procedure InputIL()
-- Read the IL into several Euphoria variables.
-- Must match OutputIL() in il.e
	integer c1, c2, start
	atom size, checksum
	sequence switches
	
	c1 = getc(current_db)
	if c1 = '#' then
		--ignore shebang line
		if atom(gets(current_db)) then
		end if
		c1 = getc(current_db)
	end if
	
	c2 = getc(current_db) -- IL version
	if c1 != IL_MAGIC or c2 < 10 then
		fatal( GetMsgText(296))
	end if
	
	if c2 != IL_VERSION then
		fatal( GetMsgText(297) )
	end if
	
	-- read size
	size = (getc(current_db) - 32) +
		   (getc(current_db) - 32) * 200 +
		   (getc(current_db) - 32) * 40000 +
		   (getc(current_db) - 32) * 8000000
	
	-- read checksum
	checksum = (getc(current_db) - 32) +
			   (getc(current_db) - 32) * 200 +
			   (getc(current_db) - 32) * 40000 +
			   (getc(current_db) - 32) * 8000000
	
	start = where(current_db)
	
	verify_checksum(size, checksum) -- reads rest of file
	
	-- restart at beginning
	if seek(current_db, start) != 0 then
		fatal( GetMsgText(298) )
	end if

	init_compress()
	misc = fdecompress(0)
	max_stack_per_call = misc[1]
	AnyTimeProfile = misc[2]
	AnyStatementProfile = misc[3]
	sample_size = misc[4]
	gline_number = misc[5]
	known_files = misc[6]
	
	SymTab = fdecompress(0)
	slist = fdecompress(0)
	file_include = fdecompress(0)
	switches = fdecompress(0)
	include_matrix = fdecompress(0)
end procedure

sequence cl
object filename

cl = command_line()
Argv = cl
Argc = length( Argv )

-- open our own .exe file
ifdef UNIX then
	filename = e_path_find(cl[1])
	if sequence(filename) then
		current_db = open(filename, "rb")
	else
		filename = cl[1]
		current_db = -1
	end if
elsedef
	filename = cl[1]
	current_db = open(filename, "rb") 
end ifdef

if current_db = -1 then
	fatal( GetMsgText(299, 1, {filename}) )
end if

-- Must be less than or equal to actual backend size.
-- We seek to this position and then search for the marker.

ifdef FREEBSD or OSX then
	constant OUR_SIZE = 150000 -- eub for FreeBSD (not compressed)

elsifdef LINUX then
	constant OUR_SIZE = 150000  -- eub for Linux

elsedef
	constant OUR_SIZE = 67000  -- eub.exe (upx compression)
end ifdef

if seek(current_db, OUR_SIZE) then
	fatal( GetMsgText(300) )
end if

object line

-- search for Euphoria code 
-- either tacked on the end of our .exe, 
-- or as a command-line filename

while 1 do
	line = gets(current_db)
	if atom(line) then
		-- EOF, no eu code found in our .exe
		-- see if a filename was specified on the command line
		
		if length(cl) > 2 then
			filename = cl[3]
			if filename[$] = '.' then
				filename = filename[1 .. $-1]
			end if
			line = fileext(cl[3])
			if length(line) = 0 then
				filename &= ".il"
			end if
			close(current_db)
			line = e_path_find(filename)
			if sequence(line) then
				filename = line
				current_db = open(filename, "rb")
			else
				current_db = -1
			end if

			if current_db != -1 then
				il_file = 1
				exit
			end if
			fatal( GetMsgText(301, , {filename}))
		end if
		fatal( GetMsgText(302) )
	end if
	if equal(line, IL_START) then
		exit
	end if
end while

integer save_first_rand
save_first_rand = rand(1000000000)

InputIL() -- read Euphoria data structures from compressed IL 
		  -- in our own .exe file, or from a .il file, and descramble them

constant M_SET_RAND = 35
machine_proc(M_SET_RAND,save_first_rand)

BackEnd(il_file)-- convert Euphoria data structures to memory and call C back-end

