'  ____	        ____
' | __ )  __ _ / ___|___  _ __
' |  _ \ / _` | |   / _ \| '_ \
' | |_) | (_| | |__| (_) | | | |   --= A BaCon BASIC-to-C converter =--
' |____/ \__,_|\____\___/|_| |_|
'
' Peter van Eerten - March 2009/July 2022. License: MIT License.
'
'---------------------------------------------------------------------------------------------------------------------
' CREDITS to all people of the BaCon forum. Without them BaCon would not be as it is now.
'---------------------------------------------------------------------------------------------------------------------
'
' Though BaCon is much more powerful than KSH or BASH, this program follows the same structure
' and approach as the existing shell script implementation where possible.
'
' The reason for this is maintainability and consistency: a bug should show up in all versions
' and should be solved in all versions.
'
'---------------------------------------------------------------------------------------------------------------------
' GLOBAL INITIALIZATIONS
'---------------------------------------------------------------------------------------------------------------------

' Lower bound of array starts with 1
OPTION BASE 1

' Prevent parse errors
OPTION COLLAPSE TRUE

' Version of BACON
CONST g_VERSION$ = "4.5"

' Our numerical environment is POSIX
SETENVIRON "LC_NUMERIC", "POSIX"

' Verify that BaCon has been compiled with correct version
IF VERSION$ != g_VERSION$ THEN
	EPRINT "System error: this BaCon binary was compiled with a previous BaCon version and therefore may not function correctly."
	EPRINT "Recompile BaCon with the Shell implementation version ", g_VERSION$, "."
	END 1
END IF

'  Solaris
IF INSTR(OS$, "SunOS") THEN g_LDFLAGS$ = "-lnsl -lsocket"

' Global to define '$', '%' and '#'-replacement
CONST g_STRINGSIGN$ = "__b2c__string_var"
CONST g_LONGSIGN$ = "__b2c__long_var"
CONST g_FLOATSIGN$ = "__b2c__float_var"
CONST g_RANGEOP$ = "BETWEEN "

' Intense Flag for ASCII editor
DECLARE Color_Intense = 0
' Line Number Flag for ASCII editor
DECLARE Line_Number_Active = 0

' Needed to prevent accidental variable names using C keywords
CONST g_C_KEYWORDS$ = "^(asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|y0|y1|yn|y0f|y1f|ynf|y0l|y1l|ynl)$"

'----------------------------------------------------------------------------------------------

FUNCTION Get_Var$(VAR arg$ SIZE amount)

	LOCAL var$, result$, record$

	' Get rid of assignment notation
	IF INSTR(arg$[1], "=") THEN
		var$ = LEFT$(arg$[1], INSTR(arg$[1], "=")-1)
	ELSE
		var$ = arg$[1]
	ENDIF

	' Get rid of '*' sign in variable name
	var$ = EXTRACT$(var$, CHR$(42))

	' Get rid of '.' sign within variable name
	IF AMOUNT(var$, ".") > 1 THEN
		record$ = TOKEN$(var$, 1, ".")
		var$ = TOKEN$(var$, 2, ".")
	ELSE
		record$ = g_RECORDVAR$
	ENDIF
	record$ = CHOP$(EXTRACT$(record$,"\\[.*", TRUE))

	' If there is a record name then add a "."
	IF LEN(record$) THEN record$ = record$ & "."

	' Get rid of array notation
	IF INSTR(var$, "[") THEN var$ = LEFT$(var$, INSTR(var$, "[")-1)

	' Get rid of brackets in case of function pointer or assoc var
	IF INSTR(var$, "(") THEN var$ = LEFT$(var$, INSTR(var$, "(")-1)

	' Get rid of type signs
	var$ = REPLACE$(var$, "$", g_STRINGSIGN$)
	var$ = REPLACE$(var$, "#", g_FLOATSIGN$)
	var$ = REPLACE$(var$, "%", g_LONGSIGN$)

	result$ = g_ALL_MAIN_VARS$(record$ & var$)
	IF amount > 1 AND NOT(LEN(result$)) THEN result$ = g_ALL_FUNC_VARS$(record$ & var$, arg$[2])

	RETURN result$

END FUNCTION

'----------------------------------------------------------------------------------------------

SUB Save_Main_Var(STRING var$, STRING type$)

	' Make sure the asterisk is attached to type
	IF LEFT$(var$, 1) = "*" THEN
		type$ = type$ & FILL$(COUNT(var$, 42), 42)
		var$ = EXTRACT$(var$, CHR$(42))
	END IF

	' Get rid of assignment notation
	IF INSTR(var$, "=") THEN
		var$ = LEFT$(var$, INSTR(var$, "=")-1)
	ENDIF

	' Get rid of array notation
	IF INSTR(var$, "[") THEN
		var$ = LEFT$(var$, INSTR(var$, "[")-1)
	ENDIF

	IF LEN(g_RECORDVAR$) THEN
		IF LEN(var$) THEN
			g_ALL_MAIN_VARS$(CHOP$(EXTRACT$(g_RECORDVAR$,"\\[.*", TRUE)) & "." & CHOP$(var$)) = type$
		ELSE
			g_ALL_MAIN_VARS$(CHOP$(EXTRACT$(g_RECORDVAR$,"\\[.*", TRUE))) = type$
		ENDIF
	ELSE
		g_ALL_MAIN_VARS$(CHOP$(var$)) = type$
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Save_Func_Var(STRING var$, STRING func$, STRING type$)

	' Make sure the asterisk is attached to type
	IF LEFT$(var$, 1) = "*" THEN
		type$ = type$ & FILL$(COUNT(var$, 42), 42)
		var$ = EXTRACT$(var$, CHR$(42))
	END IF

	' Get rid of assignment notation
	IF INSTR(var$, "=") THEN
		var$ = LEFT$(var$, INSTR(var$, "=")-1)
	ENDIF

	' Get rid of array notation
	IF INSTR(var$, "[") THEN
		var$ = LEFT$(var$, INSTR(var$, "[")-1)
	ENDIF

	IF LEN(g_RECORDVAR$) THEN
		g_ALL_FUNC_VARS$(CHOP$(EXTRACT$(g_RECORDVAR$,"\\[.*", TRUE)) & "." & CHOP$(var$), func$) = type$
	ELSE
		g_ALL_FUNC_VARS$(CHOP$(var$), func$) = type$
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Debug_Vars

	LOCAL xxx, many

	PRINT
	LOOKUP g_ALL_MAIN_VARS$ TO mainvar$ SIZE many
	IF many THEN
		FOR xxx = 1 TO many
			PRINT g_ALL_MAIN_VARS$(mainvar$[xxx]), ":MAIN:", mainvar$[xxx], " ";
		NEXT
		PRINT
	ENDIF

	LOOKUP g_ALL_FUNC_VARS$ TO funcvar$ SIZE many
	IF many THEN
		FOR xxx = 1 TO many
			PRINT g_ALL_FUNC_VARS$(funcvar$[xxx]), ":", TOKEN$(funcvar$[xxx], 2), ":", TOKEN$(funcvar$[xxx], 1), " ";
		NEXT
		PRINT
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Register_Numeric(arg$, isfloat)

	IF NOT(LEN(Get_Var$(arg$, g_FUNCNAME$))) THEN
		' Variable may not be class, array member, record, assoc, or pointer
		IF NOT(INSTR(arg$, "::")) AND NOT(REGEX(arg$, "\\[.*\\]")) AND NOT(TALLY(arg$, ".")) AND NOT(REGEX(arg$, "\\(.*\\)")) AND NOT(TALLY(arg$, "->")) THEN
			IF g_OPTION_EXPLICIT$ = "1" OR g_OPTION_EXPLICIT$ = "TRUE" THEN
				EPRINT NL$, "Syntax error: OPTION EXPLICIT forces explicit variable declaration at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			ENDIF
			IF isfloat OR REGEX(arg$, g_FLOATSIGN$ & "$") THEN
				WRITELN "double ", arg$, ";" TO g_HFILE
				Save_Main_Var(arg$, "double")
			ELSE
				WRITELN g_VARTYPE$, " ", arg$, ";" TO g_HFILE
				Save_Main_Var(arg$, g_VARTYPE$)
			ENDIF
		ENDIF
	ENDIF

ENDSUB

SUB Register_String(arg$)

	IF NOT(LEN(Get_Var$(arg$, g_FUNCNAME$))) THEN
		' Variable may not be record, nor pointer
		IF NOT(TALLY(arg$, ".")) AND NOT(TALLY(arg$, "->")) THEN
			IF g_OPTION_EXPLICIT$ = "1" OR g_OPTION_EXPLICIT$ = "TRUE" THEN
				EPRINT NL$, "Syntax error: OPTION EXPLICIT forces explicit variable declaration at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			ENDIF
			WRITELN "char* ", arg$, " = NULL;" TO g_HFILE
			Save_Main_Var(arg$, "char*")
		ENDIF
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------
' Mini parser to obtain chunk of text separated by comma. The comma in function arguments is ignored.
' This function will NOT attach the last ")" in case of a function and then jump out.

FUNCTION Mini_Parser$(VAR exp$ SIZE amount)

	LOCAL in_string, escaped, x TYPE unsigned long
	LOCAL in_func

	FOR x = 1 TO LEN(exp$[1])
		IF amount = 2 THEN
			IF MID$(exp$[1], x, LEN(exp$[2])) = exp$[2] THEN
				IF ISFALSE(in_string) AND ISFALSE(in_func) THEN BREAK
			ENDIF
		ENDIF
		SELECT ASC(MID$(exp$[1], x, 1))
			CASE 44;
			CASE 59
				IF ISFALSE(in_string) AND ISFALSE(in_func) THEN BREAK
			CASE 92
				IF escaped THEN
					escaped = FALSE
				ELSE
					escaped = TRUE
				ENDIF
			CASE 34
				IF ISFALSE(escaped) THEN in_string = NOT(in_string)
				escaped = FALSE
			CASE 40
				IF ISFALSE(in_string) THEN INCR in_func
				escaped = FALSE
			CASE 41
				IF ISFALSE(in_string) THEN DECR in_func
				escaped = FALSE
			DEFAULT
				escaped = FALSE
		END SELECT
		IF in_func < 0 THEN BREAK
	NEXT

	RETURN LEFT$(exp$[1], x-1)

END FUNCTION

'----------------------------------------------------------------------------------------------

FUNCTION Check_String_Type(arg$)

	LOCAL type$

	' Get rid of casting in array indicators
	arg$ = EXTRACT$(arg$, "\\(uint64_t\\)", TRUE)

	' Remove part after '(' in case of function or assoc array
	arg$ = IIF$(TALLY(arg$, "("), TOKEN$(arg$, 1, "("), arg$)

	' It contains double quotes or ends with '$' symbol (Parse_Equation)
	IF INSTR(arg$, CHR$(34)) OR RIGHT$(arg$, 1) = "$" THEN
		RETURN TRUE
	ELSE
		' Check variable registration
		type$ = Get_Var$(arg$, g_FUNCNAME$)

		IF LEN(type$) THEN
			IF INSTR(type$, "char*") OR INSTR(type$, "STRING") THEN
				RETURN TRUE
			ELSE
				RETURN FALSE
			ENDIF
		ELIF INSTR(arg$, g_STRINGSIGN$) THEN
			RETURN TRUE
		ELSE
			RETURN FALSE
		ENDIF
	ENDIF

END FUNCTION

'----------------------------------------------------------------------------------------------

SUB Assign_To_String(from$, to$, memsize$)

	LOCAL lft$, str$

	IF REGEX(to$, "\\(.*\\)$") THEN
		str$ = INBETWEEN$(to$, "(", ")", 2)
		lft$ = MID$(to$, 1, INSTR(to$, "(")-1)
		WRITELN "__b2c__hash_add_str(__b2c__assoc_", lft$, ", ", from$, ", ", str$, ");" TO g_CFILE
		WRITELN "free(", from$, "); ", from$, " = NULL;" TO g_CFILE
		' Check for relations
		CALL Relate_Recurse(lft$, str$, to$, -1)
	ELIF Check_String_Type(to$) THEN
		IF INSTR(to$, g_STRINGSIGN$) THEN
			WRITELN "__b2c_Swap_String(&", to$, ", &", from$, ");" TO g_CFILE
			WRITELN "__b2c__STRFREE(", from$, "); ", from$, " = NULL;" TO g_CFILE
		ELSE
			WRITELN "__b2c__STRFREE(", to$, "); ", to$, " = ", from$, ";" TO g_CFILE
		END IF
	ELSE
		WRITELN "memcpy((void*)(", to$, "), (void*)", from$, ", ", memsize$, "); free(", from$, ");" TO g_CFILE
	ENDIF

ENDSUB

'----------------------------------------------------------------------------------------------

SUB Assign_To_Number(from$, to$, flag)

	LOCAL type$, lft$, str$

	' Get the type
	IF REGEX(to$, "\\(.*\\)$") THEN
		type$ = Get_Var$("__b2c__assoc_" & to$, g_FUNCNAME$)
	ELSE
		type$ = Get_Var$(to$, g_FUNCNAME$)
	ENDIF

	' Make sure internal var is copied to var of program
	IF REGEX(to$, "\\(.*\\)$") THEN
		str$ = INBETWEEN$(to$, "(", ")", 2)
		lft$ = MID$(to$, 1, INSTR(to$, "(")-1)
		IF flag THEN
			IF INSTR(type$, "double") OR INSTR(type$, "float") OR INSTR(type$, "FLOATING") THEN
				WRITELN "__b2c__assoc_", lft$, "_eval = atof(", from$, ");" TO g_CFILE
			ELIF INSTR(type$, "long") OR INSTR(type$, "NUMBER") THEN
				WRITELN "__b2c__assoc_", lft$, "_eval = atol(", from$, ");" TO g_CFILE
			ELSE
				WRITELN "__b2c__assoc_", lft$, "_eval = atoi(", from$, ");" TO g_CFILE
			END IF
			WRITELN "free(", from$, "); ", from$, " = NULL;" TO g_CFILE
		ELSE
			WRITELN "__b2c__assoc_", lft$, "_eval = (", type$, ")(", from$, ");" TO g_CFILE
		ENDIF
		WRITELN "__b2c__hash_add(__b2c__assoc_", lft$, ", &__b2c__assoc_", lft$, "_eval, ", str$, ");" TO g_CFILE
		' Check for relations
		CALL Relate_Recurse(lft$, str$, to$, -1)
	ELSE
		IF flag THEN
			IF INSTR(type$, "double") OR INSTR(type$, "float") OR INSTR(type$, "FLOATING") THEN
				WRITELN to$, " = atof(", from$, ");" TO g_CFILE
			ELIF INSTR(type$, "long") OR INSTR(type$, "NUMBER") THEN
				WRITELN to$, " = atol(", from$, ");" TO g_CFILE
			ELSE
				WRITELN to$, " = atoi(", from$, ");" TO g_CFILE
			END IF
			WRITELN "free(", from$, "); ", from$, " = NULL;" TO g_CFILE
		ELSE
			WRITELN to$, " = (", type$, ")(", from$, ");" TO g_CFILE
		ENDIF
	END IF

ENDSUB

'----------------------------------------------------------------------------------------------

SUB Print_Element (STRING arg$, STRING std$)

	' Check if var is string var
	IF Check_String_Type(arg$) THEN
		WRITELN "__b2c__assign = (char*)", arg$, "; if(__b2c__assign != NULL) { fputs(__b2c__assign, ", std$, "); }" TO g_CFILE
	ELSE
		WRITELN "fputs(STR", g_STRINGSIGN$, "(", arg$, "), ", std$, ");" TO g_CFILE
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Print(STRING arg$, STRING std$)

	LOCAL exp$, form$, to$, token$, str$, lft$
	LOCAL size, total

	' Check if argument
	IF ISTRUE(LEN(arg$)) THEN

		' Get the arguments
		PARSE COLLAPSE$(arg$) WITH "PRINT * FORMAT * TO * SIZE *" TO match$ SIZE total
		exp$ = IIF$(total > 0, match$[1])
		form$ = IIF$(total > 1, match$[2])
		to$ = IIF$(total > 2, match$[3])
		size = IIF(total > 3, VAL(match$[4]), g_BUFFER_SIZE)

		IF LEN(form$) THEN
			IF LEN(to$) THEN
				' Check if var is string var
				IF REGEX(to$, g_STRINGSIGN$ & "$") THEN
					Register_String(to$)
				ELIF NOT(REGEX(to$, g_STRINGSIGN$ & "\\(.*\\)$")) THEN
					EPRINT NL$, "Syntax error: variable for PRINT at line ", g_COUNTER, " in file '", g_CURFILE$, "' must be string!"
					END 1
				FI
				IF REGEX(to$, "\\(.*\\)$") THEN
					str$ = INBETWEEN$(to$, "(", ")", 2)
					lft$ = MID$(to$, 1, INSTR(to$, "(")-1)
					WRITELN "snprintf(__b2c__hash_realloc_str_value(__b2c__assoc_", lft$, ", ", size, "+1, ", str$, "), ", size, "+1, ", form$, ", ", exp$, ");" TO g_CFILE
					CALL Relate_Recurse(lft$, str$, to$, -1)
				ELSE
					WRITELN to$, " = (char*)__b2c_str_realloc(", to$, ", (", size, "+1)*sizeof(char));" TO g_CFILE
					WRITELN "snprintf(", to$, ", ", size, "+1, ", form$, ", ", exp$, "); __b2c__SETLEN(", to$, ", strlen(", to$, "));" TO g_CFILE
				ENDIF
			ELSE
				WRITELN "fprintf(stdout, ", CHOP$(form$, ";", 2), ", ", exp$, ");" TO g_CFILE
			END IF
		ELSE
			' Start miniparser
			WHILE LEN(exp$)
				token$ = Mini_Parser$(exp$)
				Print_Element(CHOP$(token$), std$)
				exp$ = MID$(exp$, LEN(token$)+2)
			WEND
			' If line ends with ';' then skip newline
			IF RIGHT$(arg$, 1) <> ";" THEN
				WRITELN "fputs(\"\\n\", ", std$, ");" TO g_CFILE
			ELSE
				WRITELN "fflush(", std$, ");" TO g_CFILE
			ENDIF
		END IF
	ELSE
		WRITELN "fputs(\"\\n\", ", std$, ");" TO g_CFILE
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Input(STRING arg$)

	LOCAL type$, lft$, str$, token$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty INPUT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Start miniparser
	WHILE LEN(arg$)
		token$ = Mini_Parser$(arg$)
		arg$ = MID$(arg$, LEN(token$)+2)
		IF LEN(arg$) THEN Print_Element(CHOP$(token$), "stdout")
	WEND

	arg$ = CHOP$(token$)

	' Check if var is string var
	IF REGEX(arg$, g_STRINGSIGN$ & "$") THEN
		Register_String(arg$)
	ELSE
		Register_Numeric(arg$, FALSE)
	END IF

	' Translate function to C function
	WRITELN "__b2c__input(&__b2c__assign, ", g_OPTION_INPUT$, ");" TO g_CFILE

	IF Check_String_Type(arg$) THEN
		Assign_To_String("__b2c__assign", arg$, NULL)
	ELSE
		Assign_To_Number("__b2c__assign", arg$, 1)
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_For(STRING arg$)

	LOCAL var$, in$, from$, to$, step$
	LOCAL total

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) AND NOT(ISTOKEN(arg$, "DOWNTO")) AND NOT(ISTOKEN(arg$, "IN")) THEN
		EPRINT NL$, "Syntax error: missing IN/TO/DOWNTO in FOR statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' What kind of FOR are we dealing with
	IF ISTOKEN(arg$, "TO") OR ISTOKEN(arg$, "DOWNTO") THEN
		' Get the arguments
		PARSE COLLAPSE$(arg$) WITH "FOR * " & IIF$(ISTOKEN(arg$, "TO"), "TO", "DOWNTO") & " * STEP *" TO match$ SIZE total
		var$ = CHOP$(TOKEN$(match$[1], 1, "="))
		from$ = CHOP$(TOKEN$(match$[1], 2, "="))
		to$ = match$[2]
		step$ = IIF$(total > 2, match$[3], "1")
		IF ISTOKEN(arg$, "DOWNTO") THEN step$ = "-" & step$
	ELSE
		PARSE COLLAPSE$(arg$) WITH "FOR * IN * STEP *" TO match$ SIZE total
		var$ = match$[1]
		in$ = match$[2]
		step$ = IIF$(total > 2, match$[3], "__b2c__option_delim")
		' Define help variables
		IF LEN(g_FUNCNAME$) > 0 THEN
			IF NOT(INSTR(g_STRINGARGS$, "__b2c__forin_" & var$ & "_ptr")) THEN
				g_STRINGARGS$ = g_STRINGARGS$ & " int __b2c__forin_" & var$ & "_ptr;"
				Save_Func_Var("__b2c__forin_" & var$ & "_ptr", g_FUNCNAME$, "int")
				g_STRINGARGS$ = g_STRINGARGS$ & " char* __b2c__forin_" & var$ & "_string = NULL;"
				Save_Func_Var("__b2c__forin_" & var$ & "_string", g_FUNCNAME$, "char*")
				g_STRINGARGS$ = g_STRINGARGS$ & " char* __b2c__forin_" & var$ & "_string_org = NULL;"
				Save_Func_Var("__b2c__forin_" & var$ & "_string_org", g_FUNCNAME$, "char*")
				g_STRINGARGS$ = g_STRINGARGS$ & " char* __b2c__forin_" & var$ & "_step = NULL;"
				Save_Func_Var("__b2c__forin_" & var$ & "_step", g_FUNCNAME$, "char*")
				g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__STRFREE(__b2c__forin_" & var$ & "_string_org); __b2c__forin_" & var$ & "_string_org = NULL;"
				g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__STRFREE(__b2c__forin_" & var$ & "_step); __b2c__forin_" & var$ & "_step = NULL;"
			END IF
		ELSE
			IF NOT(LEN(Get_Var$("__b2c__forin_" & var$ & "_ptr"))) THEN
				WRITELN "int __b2c__forin_", var$, "_ptr;" TO g_HFILE
				Save_Main_Var("__b2c__forin_" & var$ & "_ptr", "int")
				WRITELN "char* __b2c__forin_", var$, "_string = NULL;" TO g_HFILE
				Save_Main_Var("__b2c__forin_" & var$ & "_string", "char*")
				WRITELN "char* __b2c__forin_", var$, "_string_org = NULL;" TO g_HFILE
				Save_Main_Var("__b2c__forin_" & var$ & "_string_org", "char*")
				WRITELN "char* __b2c__forin_", var$, "_step = NULL;" TO g_HFILE
				Save_Main_Var("__b2c__forin_" & var$ & "_step", "char*")
			END IF
		END IF
	END IF

	' Check if var is string var
	IF REGEX(var$, g_STRINGSIGN$ & "$") THEN
		Register_String(var$)
	ELIF REGEX(from$ & to$ & step$, "[0-9]\\.[0-9]") OR REGEX(Get_Var$(step$, g_FUNCNAME$), "double|float|FLOATING") THEN
		Register_Numeric(var$, TRUE)
	ELSE
		Register_Numeric(var$, FALSE)
	ENDIF

	' Check type of var, string?
	IF Check_String_Type(var$) THEN
		WRITELN "if(__b2c__forin_", var$, "_string_org) { free(__b2c__forin_", var$, "_string_org); } __b2c__forin_", var$, "_string_org = __b2c__strdup(", in$, "); __b2c__forin_", var$, "_string = __b2c__forin_", var$, "_string_org;" TO g_CFILE
		WRITELN "if(__b2c__forin_", var$, "_step) { free(__b2c__forin_", var$, "_step); } __b2c__forin_", var$,"_step = __b2c__strdup(", step$, ");" TO g_CFILE
		WRITELN "__b2c__forin_", var$, "_ptr = __b2c__for_amount(__b2c__forin_", var$, "_string, __b2c__forin_", var$, "_step);" TO g_CFILE
		WRITELN "for(; __b2c__forin_", var$, "_ptr > 0; __b2c__forin_", var$, "_ptr--) { __b2c__for_item(&__b2c__forin_", var$, "_string, __b2c__forin_", var$, "_step, &", var$, ");" TO g_CFILE
	ELSE
		' Translate function to C function
		IF VAL(step$) < 0 THEN
			WRITELN "for(", var$," = ", from$, "; ", var$, " >= ", to$, ";", var$, " += ", step$, "){" TO g_CFILE
		ELSE
			WRITELN "for(", var$," = ", from$, "; ", var$, " <= ", to$, ";", var$, " += ", step$, "){" TO g_CFILE
		END IF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_While(arg$)

	PARSE COLLAPSE$(arg$) WITH "WHILE * DO" TO match$

	WRITELN "while(", Parse_Equation$(match$[1]), "){" TO g_CFILE

END SUB

'----------------------------------------------------------------------------------------------
' $1: name of ASSOC variable
' $2: name of index
' $3: actual value to assign
' $4: recursion level

SUB Relate_Recurse(STRING var$, STRING str$, STRING tmp$, NUMBER lvl)

	LOCAL rel$
	LOCAL ctr

	' Check endless recursion
	INCR lvl
	IF lvl > g_RELATE_CTR THEN
		EPRINT NL$, "Syntax error: endless recursion in RELATE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Now add relation
	FOR ctr = 0 TO g_RELATE_CTR
		IF TOKEN$(g_RELATE$[ctr], 1) = var$ THEN
			rel$ = TOKEN$(g_RELATE$[ctr], 2)
			IF INSTR(rel$, g_STRINGSIGN$) THEN
				WRITELN "__b2c__hash_add_str(__b2c__assoc_", rel$, ", ", tmp$, ", ", str$, ");" TO g_CFILE
			ELSE
				WRITELN "__b2c__assoc_", rel$, "_eval = " , tmp$, "; __b2c__hash_add(__b2c__assoc_", rel$, ", &__b2c__assoc_", rel$, "_eval, ", str$, ");" TO g_CFILE
			END IF
			Relate_Recurse(rel$, str$, tmp$, lvl)
		END IF
	NEXT

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Let(STRING arg$)

	LOCAL x TYPE unsigned long
	LOCAL in_string, escaped, pos, in_func
	LOCAL var$, tmp$, str$, lft$, rel$, ptr$, type$, item$

	' Start miniparser to find last unquoted '='
	FOR x = 1 TO LEN(arg$)
		SELECT ASC(MID$(arg$, x, 1))
			CASE 92
				IF escaped THEN
					escaped = FALSE
				ELSE
					escaped = TRUE
				FI
			CASE 34
				IF ISFALSE(escaped) THEN in_string = NOT(in_string)
				escaped = FALSE
			CASE 40
				IF ISFALSE(in_string) THEN INCR in_func
				escaped = FALSE
			CASE 41
				IF ISFALSE(in_string) THEN DECR in_func
				escaped = FALSE
			CASE 61
				IF ISFALSE(in_string) AND ISFALSE(in_func) THEN pos = x
				escaped = FALSE
			DEFAULT
				escaped = FALSE
		END SELECT
	NEXT

	' Check if there is an assignment at all, if not exit
	IF NOT(pos) THEN
		IF g_IGNORE_PARSE$ = "0" OR g_IGNORE_PARSE$ = "FALSE" THEN
			WRITELN arg$, ";" TO g_CFILE
			EXIT SUB
		ELSE
			EPRINT NL$, "Syntax error: could not parse line ", g_COUNTER, " in file '", g_CURFILE$, "': ", CHR$(34), arg$, CHR$(34)
			END 1
		END IF
	END IF

	' Get the variablename without surrounding spaces
	var$ = CHOP$(LEFT$(arg$, pos - 1))
	tmp$ = CHOP$(MID$(arg$, pos + 1))

	' Check for MEMORY allocation
	IF REGEX(tmp$, "[ \\t]*MEMORY[ \\t]*\\(") OR REGEX(tmp$, "[ \\t]*BLOAD[ \\t]*\\(") THEN g_SEMANTIC_MEMFREE$(var$) = "'" & var$ & "' at line " & STR$(g_COUNTER) & " in file '" & g_CURFILE$ & "'"

	' Check if var is string var
	IF REGEX(var$, g_STRINGSIGN$ & "$") AND NOT(ISTOKEN(g_DYNAMICARRAYS$, var$ & "@" & g_FUNCNAME$)) THEN
		Register_String(var$)
	ELIF NOT(INSTR(var$, "=")) AND NOT(TALLY(var$, "->")) THEN
		IF REGEX(tmp$, "[0-9]\\.[0-9]") AND NOT(INSTR(tmp$, CHR$(34))) THEN
			Register_Numeric(EXTRACT$(var$, "[\\+\\-\\*/% ]", TRUE), TRUE)
		ELSE
			Register_Numeric(EXTRACT$(var$, "[\\+\\-\\*/% ]", TRUE), FALSE)
		ENDIF
	END IF

	' Check if there is associative array assignment
	IF REGEX(var$, "\\(.*\\)$") THEN
		lft$ = LEFT$(var$, INSTR(var$, "(") - 1)
		IF REGEX(var$, "\\(\\)$") THEN
			str$ = LEFT$(tmp$, INSTR(tmp$, "(") - 1)
			IF INSTR(lft$, g_STRINGSIGN$) THEN
				WRITELN "__b2c__hash_dup_str(__b2c__assoc_", str$, ", __b2c__assoc_", lft$, ");" TO g_CFILE
			ELSE
				WRITELN "__b2c__hash_dup(__b2c__assoc_", str$, ", __b2c__assoc_", lft$, ");" TO g_CFILE
			ENDIF
		ELSE
			str$ = INBETWEEN$(var$, "(", ")", 2)
			IF INSTR(lft$, g_STRINGSIGN$) THEN
				WRITELN "__b2c__hash_add_str(__b2c__assoc_", lft$, ", ", tmp$, ", ", str$, ");" TO g_CFILE
			ELSE
				WRITELN "__b2c__assoc_", lft$, "_eval = ", tmp$, "; __b2c__hash_add(__b2c__assoc_", lft$, ", &__b2c__assoc_", lft$, "_eval, ", str$, ");" TO g_CFILE
			END IF
			' Check for relations
			Relate_Recurse(lft$, str$, tmp$, -1)
		ENDIF

		' Is there an array variable without subscript?
	ELIF NOT(INSTR(var$, "[")) AND ISTOKEN(g_DYNAMICARRAYS$, var$ & "@" & g_FUNCNAME$) THEN
		IF INSTR(var$, g_STRINGSIGN$) THEN WRITELN "__b2c__free_str_array_members(&" & var$ & ", " & STR$(g_OPTION_BASE) & ", " & var$ & "__b2c_array);" TO g_CFILE
		WRITELN "free(", var$, ");" TO g_CFILE
		WRITELN g_WITHVAR$, arg$, ";" TO g_CFILE

		' Do we have a STRING variable or STRING array?
	ELIF Check_String_Type(var$) AND REGEX(var$, g_STRINGSIGN$) THEN
		type$ = Get_Var$(var$, g_FUNCNAME$)
		IF INSTR(type$, "const") THEN
			WRITELN g_WITHVAR$, var$, " = (char*)__b2c__strdup((const char*)", tmp$, ");" TO g_CFILE
			IF ISTRUE(LEN(g_FUNCNAME$)) THEN
				Save_Func_Var(var$, g_FUNCNAME$, CHOP$(EXTRACT$(type$, "const")))
			ELSE
				Save_Main_Var(var$, CHOP$(EXTRACT$(type$, "const")))
			ENDIF
		ELSE
			' Make sure to handle string pointers
			IF Check_String_Type(tmp$) THEN
				WRITELN g_WITHVAR$, var$, " = __b2c_Copy_String(", g_WITHVAR$, var$, ", ", tmp$, ");" TO g_CFILE
			ELSE
				WRITELN "__b2c__STRFREE(", g_WITHVAR$, var$, ");", g_WITHVAR$, var$, " = __b2c__strdup((const char*)", tmp$, ");" TO g_CFILE
			ENDIF
		ENDIF
		' Also check if string var already is used for IMPORT, if so, perform dlopen again
		ptr$ = EXTRACT$(var$, "[[:punct:]]", TRUE)
		IF LEN(Get_Var$("__b2c__dlopen__pointer_" & ptr$)) THEN
			WRITELN "__b2c__dlopen__pointer_", ptr$, " = dlopen(", var$, ", RTLD_LAZY);" TO g_CFILE
		END IF
		' Check for array member in RECORD
		IF INSTR(var$, ".") AND REGEX(var$, "\\[.*\\]\\.") AND LEN(g_FUNCNAME$) AND NOT(LEN(Get_Var$(var$))) THEN
			IF NOT(INSTR(g_LOCALSTRINGS$, var$)) AND NOT(REGEX(var$, "\\[.*\\]$")) THEN
				g_LOCALSTRINGS$ = var$ & " " & g_LOCALSTRINGS$
			ENDIF
		ENDIF
		' Pointer type
	ELIF TALLY(var$, "->") THEN
		WRITELN g_WITHVAR$, arg$, ";" TO g_CFILE
		' Pointer to string
	ELIF NOT(REGEX(var$, g_STRINGSIGN$ & "$")) AND REGEX(tmp$, g_STRINGSIGN$ & "$") THEN
		type$ = EXTRACT$(Get_Var$(var$, g_FUNCNAME$), "static")
		WRITELN g_WITHVAR$, var$, "=(", type$, ")(", tmp$, ");" TO g_CFILE
		' Numeric or foreign type
	ELSE
		type$ = EXTRACT$(Get_Var$(var$, g_FUNCNAME$), "static")
		' Float and not assoc
		IF REGEX(type$, "float|double|FLOATING") AND NOT(INSTR(type$, "*")) THEN
			' Cast the expression to type of variable, divide symbol needs extra cast
			WRITELN g_WITHVAR$, var$, "=(", type$, ")(", DELIM$(tmp$, "/", "/(" & type$ & ")"), ");" TO g_CFILE
		ELIF REGEX(var$, ".*\\[.*\\].*") AND REGEX(type$, ".*\\*.*") THEN
			WRITELN g_WITHVAR$, arg$, ";" TO g_CFILE
			' If var is pointer then skip casting
		ELIF LEN(type$) AND NOT(INSTR(var$, "*")) THEN
			WRITELN g_WITHVAR$, var$, "=(", type$, ")(", tmp$, ");" TO g_CFILE
			' Other type
		ELSE
			WRITELN g_WITHVAR$, arg$, ";" TO g_CFILE
		ENDIF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Open(STRING arg$)

	LOCAL check
	LOCAL var$, mode$, handle$, from$ = "NULL"

	' Check if FOR is available
	IF NOT(ISTOKEN(arg$, "FOR")) THEN
		EPRINT NL$, "Syntax error: missing FOR in OPEN statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Check if AS is available
	IF NOT(ISTOKEN(arg$, "AS")) THEN
		EPRINT NL$, "Syntax error: missing AS in OPEN statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "FROM") THEN
		PARSE COLLAPSE$(arg$) WITH "OPEN * FOR * FROM * AS *" TO match$
		from$ = match$[3]
		arg$ = APPEND$(HEAD$(arg$, ISTOKEN(arg$, "FROM")-1), 0, LAST$(arg$, ISTOKEN(arg$, "AS")-1))
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "OPEN * FOR * AS *" TO match$
	var$ = match$[1]
	mode$ = match$[2]
	handle$ = match$[3]

	' Check if var is string var
	IF REGEX(handle$, g_STRINGSIGN$ & "$") AND mode$ <> "MEMORY" THEN
		EPRINT NL$, "Syntax error: variable for OPEN at line ", g_COUNTER, " in file '", g_CURFILE$, "' cannot be string!"
		END 1
	END IF

	' Check for OPEN/CLOSE pair, keep the last
	g_SEMANTIC_OPENCLOSE$(handle$) = "'" & handle$ & "' at line " & STR$(g_COUNTER) & " in file '" & g_CURFILE$ & "'"

	' Check if variable was declared
	IF NOT(INSTR(handle$, ".")) THEN
		check = LEN(Get_Var$(handle$, g_FUNCNAME$))
	ELSE
		check = TRUE
	FI

	' File or dir?
	IF ISFALSE(check) THEN
		IF g_OPTION_EXPLICIT$ = "1" OR g_OPTION_EXPLICIT$ = "TRUE" THEN
			EPRINT NL$, "Syntax error: OPTION EXPLICIT forces explicit variable declaration at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		ENDIF
	ENDIF

	IF mode$ = "DIRECTORY" THEN
		IF ISFALSE(check) THEN
			WRITELN "DIR* ", handle$, ";" TO g_HFILE
			Save_Main_Var(handle$, "DIR*")
		END IF
	ELIF mode$ = "MEMORY" THEN
		IF ISFALSE(check) THEN
			WRITELN "char* ", handle$, " = NULL;" TO g_HFILE
			Save_Main_Var(handle$, "char*")
		END IF
		IF NOT(LEN(Get_Var$("__b2c_mem_" & handle$, g_FUNCNAME$))) THEN
			WRITELN "long __b2c_mem_", handle$, ";" TO g_HFILE
			Save_Main_Var("__b2c_mem_" & handle$, "long")
		END IF
	ELIF mode$ = "NETWORK" OR mode$ = "SERVER" OR mode$ = "UDP" OR mode$ = "DEVICE" THEN
		IF ISFALSE(check) THEN
			WRITELN "uintptr_t ", handle$, ";" TO g_HFILE
			Save_Main_Var(handle$, "uintptr_t")
		END IF
	ELSE
		IF ISFALSE(check) THEN
			WRITELN "FILE* ", handle$, ";" TO g_HFILE
			Save_Main_Var(handle$, "FILE*")
		END IF
	END IF

	' Convert to C syntax
	IF mode$ = "READING" THEN
		WRITELN handle$, " = fopen((const char*)", var$, ", \"r\");" TO g_CFILE
		WRITELN "if(", handle$, " == NULL){if(__b2c__trap){ERROR = 2; if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR READING\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELIF mode$ = "WRITING" THEN
		WRITELN handle$, " = fopen((const char*)", var$, ", \"w\");" TO g_CFILE
		WRITELN "if(", handle$, " == NULL){if(__b2c__trap){ERROR = 2; if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR WRITING\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELIF mode$ = "APPENDING" THEN
		WRITELN handle$, " = fopen((const char*)", var$, ", \"a\");" TO g_CFILE
		WRITELN "if(", handle$, " == NULL){if(__b2c__trap){ERROR = 2; if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR APPENDING\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELIF mode$ = "READWRITE" THEN
		WRITELN handle$, " = fopen((const char*)", var$, ", \"r+\");" TO g_CFILE
		WRITELN "if(", handle$, " == NULL){if(__b2c__trap){ERROR = 2; if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR READWRITE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELIF mode$ = "DIRECTORY" THEN
		WRITELN handle$, " = opendir(", var$, ");" TO g_CFILE
		WRITELN "if(", handle$, " == NULL){if(__b2c__trap){ERROR = 2; if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR DIRECTORY\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELIF mode$ = "MEMORY" THEN
		IF INSTR(handle$, g_STRINGSIGN$) THEN WRITELN "__b2c__STRFREE(", handle$, ");" TO g_CFILE
		WRITELN handle$, " = (char*)", var$, "; __b2c_mem_", handle$, " = (uintptr_t)", var$, ";" TO g_CFILE
		WRITELN "if(__b2c__trap){if(__b2c__memory__check(", handle$, ", sizeof(__b2c__MEMTYPE))) {ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR MEMORY\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELIF mode$ = "NETWORK" THEN
		' Network code
		WRITELN "ERROR = __b2c__network_init((uintptr_t*)&", handle$, ", ", var$, ", ", from$, ", ", g_SOCKTYPE$, ", ", g_OPTION_SOCKET, ", \"", g_NETWORKTYPE$, "\", ", g_MULTICAST_TTL, ", ", g_SCTP_STREAMS, ", __b2c__capeer, __b2c__cacerts);" TO g_CFILE
		WRITELN "if(ERROR && __b2c__trap){ if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR NETWORK\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, "; }" TO g_CFILE
	ELIF mode$ = "SERVER" THEN
		' Network code
		WRITELN "ERROR = __b2c__server_init((uintptr_t*)&", handle$, ", ", var$, ", ", g_SOCKTYPE$, ", ", g_OPTION_SOCKET, ", ", g_SCTP_STREAMS, ");" TO g_CFILE
		WRITELN "if(ERROR && __b2c__trap){ if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR SERVER\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, "; }" TO g_CFILE
	ELIF mode$ = "DEVICE" THEN
		WRITELN handle$, " = open(", var$, ", __b2c__option_open, S_IRUSR|S_IWUSR);" TO g_CFILE
		WRITELN "if(", handle$, " < 0){if(__b2c__trap){ERROR = 32; if(!__b2c__catch_set) RUNTIMEERROR(\"OPEN FOR DEVICE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	END IF
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Readln(STRING arg$)

	LOCAL var$, from$

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "FROM")) THEN
		EPRINT NL$, "Syntax error: missing FROM in READLN statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "READLN * FROM *" TO match$
	var$ = match$[1]
	from$ = match$[2]

	' Check if var is string var
	IF NOT(Check_String_Type(var$)) THEN
		EPRINT NL$, "Syntax error: variable for READLN at line ", g_COUNTER, " in file '", g_CURFILE$, "' must be string!"
		END 1
	END IF

	' Check if var is string var
	IF REGEX(var$, g_STRINGSIGN$ & "$") THEN Register_String(var$)

	' Translate function to C function
	WRITELN "__b2c__readln(&__b2c__assign, ", from$, ");" TO g_CFILE
	Assign_To_String("__b2c__assign", var$, NULL)

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Writeln(STRING arg$)

	LOCAL var$, to$, token$, org$

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in WRITELN statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "WRITELN * TO *" TO match$
	var$ = match$[1]
	to$ = match$[2]
	org$ = var$

	' Start miniparser
	WHILE LEN(var$)
		token$ = Mini_Parser$(var$)
		Print_Element(CHOP$(token$), to$)
		var$ = MID$(var$, LEN(token$)+2)
	WEND

	IF RIGHT$(org$, 1) <> ";" THEN
		WRITELN "fputs(\"\\n\", ", to$, ");" TO g_CFILE
	ELSE
		WRITELN "fflush(", to$, ");" TO g_CFILE
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Getbyte(STRING arg$)

	LOCAL var$, from$, size$, type$, chunk$
	LOCAL total

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "FROM")) THEN
		EPRINT NL$, "Syntax error: missing FROM in GETBYTE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF MATCH(COLLAPSE$(arg$), "* CHUNK *") THEN
		PARSE COLLAPSE$(arg$) WITH "GETBYTE * FROM * CHUNK * SIZE *" TO match$ SIZE total
		chunk$ = match$[3]
		size$ = IIF$(total > 3, match$[4])
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "CHUNK")-1)
	ELIF MATCH(COLLAPSE$(arg$), "* SIZE *") THEN
		PARSE COLLAPSE$(arg$) WITH "GETBYTE * FROM * SIZE *" TO match$
		size$ = match$[3]
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "SIZE")-1)
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "GETBYTE * FROM *" TO match$
	var$ = match$[1]
	from$ = match$[2]

	' Ensure backwards compatibility
	IF LEN(size$) THEN
		IF LEN(chunk$) = 0 THEN
			chunk$ = size$
			size$ = "__b2c__counter"
		ENDIF
	ELSE
		IF LEN(chunk$) = 0 THEN chunk$ = "1"
		size$ = "__b2c__counter"
	ENDIF

	' Variable may not be array, these should be defined with DECLARE
	IF LEN(size$) AND size$ <> "__b2c__counter" THEN Register_Numeric(size$, FALSE)

	' Detect type of descriptor
	type$ = Get_Var$(from$, g_FUNCNAME$)

	' Translate function to C function
	WRITELN "if(__b2c__trap){if(__b2c__memory__check((char*)", var$, ", sizeof(__b2c__MEMTYPE))) {ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"GETBYTE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	IF INSTR(type$, "int") THEN
		WRITELN "if((", size$, " = read(", from$, ", (void*)(", var$, "), ", chunk$, ")) < 0)" TO g_CFILE
		WRITELN "{if(__b2c__trap){ERROR = 34; if(!__b2c__catch_set) RUNTIMEERROR(\"GETBYTE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELSE
		WRITELN size$, " = fread((void*)(", var$, "), sizeof(__b2c__MEMTYPE), ", chunk$, ", ", from$, ");" TO g_CFILE
	END IF
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Putbyte(STRING arg$)

	LOCAL var$, to$, size$, type$, chunk$
	LOCAL total

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in PUTBYTE statement at line at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF MATCH(COLLAPSE$(arg$), "* CHUNK *") THEN
		PARSE COLLAPSE$(arg$) WITH "PUTBYTE * TO * CHUNK * SIZE *" TO match$ SIZE total
		chunk$ = match$[3]
		size$ = IIF$(total > 3, match$[4])
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "CHUNK")-1)
	ELIF MATCH(COLLAPSE$(arg$), "* SIZE *") THEN
		PARSE COLLAPSE$(arg$) WITH "PUTBYTE * TO * SIZE *" TO match$
		size$ = match$[3]
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "SIZE")-1)
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "PUTBYTE * TO *" TO match$
	var$ = match$[1]
	to$ = match$[2]

	' Ensure backwards compatibility
	IF LEN(size$) THEN
		IF LEN(chunk$) = 0 THEN
			chunk$ = size$
			size$ = "__b2c__counter"
		ENDIF
	ELSE
		IF LEN(chunk$) = 0 THEN chunk$ = "1"
		size$ = "__b2c__counter"
	ENDIF

	' Variable may not be array, these should be defined with DECLARE
	IF LEN(size$) AND size$ <> "__b2c__counter" THEN Register_Numeric(size$, FALSE)

	' Detect type of descriptor
	type$ = Get_Var$(to$, g_FUNCNAME$)

	' Translate function to C function
	WRITELN "if(__b2c__trap){if(__b2c__memory__check((char*)", var$, ", sizeof(__b2c__MEMTYPE))) {ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"PUTBYTE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	IF INSTR(type$, "int") THEN
		WRITELN "if((", size$, " = write(", to$, ", (void*)(", var$, "), ", chunk$, ")) < 0)" TO g_CFILE
		WRITELN "{if(__b2c__trap){ERROR = 34; if(!__b2c__catch_set) RUNTIMEERROR(\"PUTBYTE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	ELSE
		WRITELN size$, " = fwrite((void*)", var$, ", sizeof(__b2c__MEMTYPE), ", chunk$, ", ", to$, "); fflush(", to$, ");" TO g_CFILE
	ENDIF
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Getfile(STRING arg$)

	LOCAL var$, from$

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "FROM")) THEN
		EPRINT NL$, "Syntax error: missing FROM in GETFILE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "GETFILE * FROM *" TO match$
	var$ = match$[1]
	from$ = match$[2]

	' Check if var is string var
	IF NOT(Check_String_Type(var$)) THEN
		EPRINT NL$, "Syntax error: variable for GETFILE at line ", g_COUNTER, " in file '", g_CURFILE$, "' must be string!"
		END 1
	END IF

	' Check if var is string var
	IF REGEX(var$, g_STRINGSIGN$ & "$") THEN Register_String(var$)

	' Translate statement to C function
	WRITELN "__b2c__getfile(&__b2c__assign, ", from$, ");" TO g_CFILE
	Assign_To_String("__b2c__assign", var$, NULL)

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Receive(STRING arg$)

	LOCAL var$, from$, size$, chunk$

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "FROM")) THEN
		EPRINT NL$, "Syntax error: missing FROM in RECEIVE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "SIZE") THEN
		size$ = LAST$(arg$, ISTOKEN(arg$, "SIZE"))
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "SIZE")-1)
	ENDIF
	IF ISTOKEN(arg$, "CHUNK") THEN
		chunk$ = LAST$(arg$, ISTOKEN(arg$, "CHUNK"))
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "CHUNK")-1)
	ELSE
		IF g_OPTION_TLS THEN
			chunk$ = "32768"
		ELSE
			chunk$ = STR$(g_BUFFER_SIZE)
		ENDIF
	ENDIF
	from$ = LAST$(arg$, ISTOKEN(arg$, "FROM"))
	arg$ = HEAD$(arg$, ISTOKEN(arg$, "FROM")-1)
	var$ = CHOP$(arg$)

	' Variable may not be array, these should be defined with DECLARE
	IF LEN(size$) THEN
		Register_Numeric(size$, FALSE)
	ELSE
		IF LEN(size$) = 0 THEN
			size$ = "__b2c__counter"
		ENDIF
	END IF

	' Check if var is string var
	IF REGEX(var$, g_STRINGSIGN$ & "$") THEN Register_String(var$)

	' Translate function to C function
	WRITELN "__b2c__assign = (char*)calloc((", chunk$, "+1), sizeof(char));" TO g_CFILE
	IF g_NETWORKTYPE$ = "SCTP" THEN
		WRITELN "if((", size$, " = sctp_recvmsg(", from$, ", (void*)__b2c__assign, ", chunk$, ", 0, 0, 0, 0)) < 0) {" TO g_CFILE
	ELSE
		' Receive from SSL socket if option was set
		IF g_OPTION_TLS THEN
			WRITELN "if(", from$, " > 0) { ", size$, " = SSL_read((SSL*)", from$, ", (void*)__b2c__assign, ", chunk$, "); } if(", size$, " <= 0) { fprintf(stderr, \"SSL READ error in line ", g_COUNTER, ": %s\\n\", ERR_error_string(SSL_get_error((SSL*)", from$, ", ", size$, "), NULL));" TO g_CFILE
		ELSE
			WRITELN "if((", size$, " = recv(", from$, ", (void*)__b2c__assign, ", chunk$,", 0)) < 0) {" TO g_CFILE
		ENDIF
	END IF
	WRITELN "if(__b2c__trap){ERROR = 14; if(!__b2c__catch_set) RUNTIMEERROR(\"RECEIVE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, "; } }" TO g_CFILE

	Assign_To_String("__b2c__assign", var$, size$)

	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Send(STRING arg$)

	LOCAL var$, to$, chunk$, size$

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in SEND statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "SIZE") THEN
		size$ = LAST$(arg$, ISTOKEN(arg$, "SIZE"))
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "SIZE")-1)
	ENDIF
	IF ISTOKEN(arg$, "CHUNK") THEN
		chunk$ = LAST$(arg$, ISTOKEN(arg$, "CHUNK"))
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "CHUNK")-1)
	ENDIF
	to$ = LAST$(arg$, ISTOKEN(arg$, "TO"))
	arg$ = HEAD$(arg$, ISTOKEN(arg$, "TO")-1)
	var$ = CHOP$(arg$)

	IF LEN(chunk$) = 0 THEN chunk$ = "strlen(" & var$ & ")"

	' Variable may not be array, these should be defined with DECLARE
	IF LEN(size$) THEN
		Register_Numeric(size$, FALSE)
	ELSE
		IF LEN(size$) = 0 THEN
			size$ = "__b2c__counter"
		ENDIF
	END IF

	' Translate function to C function
	IF g_NETWORKTYPE$ = "SCTP" THEN
		WRITELN "if((", size$, " = sctp_sendmsg(", to$, ", (void*)(", var$, "), ", chunk$, ", NULL, 0, 0, 0, 0, 0, 0)) < 0) {" TO g_CFILE
	ELSE
		' Send to SSL socket if option was set
		IF g_OPTION_TLS THEN
			WRITELN size$, " = SSL_write((SSL*)", to$, ", (const void*)(", var$, "), ", chunk$, "); if(", size$, " <= 0) { fprintf(stderr, \"SSL WRITE error: %s\\n\", ERR_error_string(SSL_get_error((SSL*)", to$, ", ", size$, "), NULL));" TO g_CFILE
		ELSE
			WRITELN "if((", size$, " = send(", to$, ", (void*)(", var$, "), ", chunk$, ", 0)) < 0) {" TO g_CFILE
		ENDIF
	ENDIF
	WRITELN "if(__b2c__trap){ERROR = 15; if(!__b2c__catch_set) RUNTIMEERROR(\"SEND\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Getline(STRING arg$)

	LOCAL var$, from$

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "FROM")) THEN
		EPRINT NL$, "Syntax error: missing FROM in GETLINE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "GETLINE * FROM *" TO match$
	var$ = match$[1]
	from$ = match$[2]

	' Check if var is string var
	IF NOT(Check_String_Type(var$)) THEN
		EPRINT NL$, "Syntax error: variable for GETLINE at line $g_COUNTER in file ", g_COUNTER, " in file '", g_CURFILE$, "' must be string!"
		END 1
	END IF

	' Check if var is string var, exclude RECORD elements
	IF REGEX(var$, g_STRINGSIGN$ & "$") THEN Register_String(var$)

	' Translate to C function
	WRITELN "__b2c__assign = __b2c__getline(&", from$, ");" TO g_CFILE
	Assign_To_String("__b2c__assign", var$, NULL)

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Putline(STRING arg$)

	LOCAL var$, to$, token$

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in PUTLINE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "PUTLINE * TO *" TO match$
	var$ = match$[1]
	to$ = match$[2]

	' Start miniparser
	WHILE LEN(var$)
		token$ = Mini_Parser$(var$)

		' Check if var is string var
		IF Check_String_Type(token$) THEN
			WRITELN "strcat(", to$, ", ", CHOP$(token$), ");", to$, "+=strlen(", CHOP$(token$), ");" TO g_CFILE
		ELSE
			WRITELN "strcat(", to$, ", STR", g_STRINGSIGN$, "(", CHOP$(token$), "));", to$, "+=strlen(STR", g_STRINGSIGN$, "(", CHOP$(token$), "));" TO g_CFILE
		END IF
		var$ = MID$(var$, LEN(token$)+2)
	WEND

	WRITELN "strcat(", to$, ", \"\\n\"); ", to$, "+=1;" TO g_CFILE

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Import(STRING arg$)

	LOCAL lib$, type$, sym$, token$, alias$, ptr$
	LOCAL total

	' Check if FROM is available
	IF NOT(ISTOKEN(arg$, "FROM")) THEN
		EPRINT NL$, "Syntax error: missing FROM in IMPORT statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Check if TYPE is available
	IF NOT(ISTOKEN(arg$, "TYPE")) THEN
		EPRINT NL$, "Syntax error: missing TYPE in IMPORT statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "IMPORT * FROM * TYPE * ALIAS *" TO match$ SIZE total
	sym$ = EXTRACT$(match$[1], CHR$(34))
	lib$ = match$[2]
	type$ = match$[3]
	IF total > 3 THEN
		alias$ = match$[4]
		g_IMPORTED$ = alias$ & " " & g_IMPORTED$
	ENDIF

	' Separate symbol and args
	IF INSTR(sym$, "(") THEN
		token$ = INBETWEEN$(sym$, "(", ")")
		sym$ = CHOP$(TOKEN$(sym$, 1, "("))
	ENDIF

	' If library is libm or libc, skip dlopen as we're linking with those anyway
	IF NOT(INSTR(lib$, "libc.so") ) AND NOT(INSTR(lib$, "libm.so")) THEN

		IF NOT(INSTR(OS$, "OSF1")) AND NOT(INSTR(OS$, "BSD")) AND NOT(INSTR(g_LDFLAGS$, "-ldl")) THEN g_LDFLAGS$ = g_LDFLAGS$ & " -ldl"

		' Create name from libname
		ptr$ = EXTRACT$(lib$, "[[:punct:]]", TRUE)

		' Check if variable was declared
		IF NOT(LEN(Get_Var$("__b2c__dlopen__pointer_" & ptr$))) THEN
			WRITELN "void* __b2c__dlopen__pointer_", ptr$, " = NULL;" TO g_HFILE
			Save_Main_Var("__b2c__dlopen__pointer_" & ptr$, "void*")
		END IF
		WRITELN "if(__b2c__dlopen__pointer_", ptr$, " == NULL){__b2c__dlopen__pointer_", ptr$, " = dlopen(", lib$, ", RTLD_LAZY); if(__b2c__dlopen__pointer_", ptr$, " == NULL){" TO g_CFILE
		WRITELN "if(__b2c__trap){ERROR = 3;if(!__b2c__catch_set) RUNTIMEERROR(\"IMPORT\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} } }" TO g_CFILE

		' Create prototype
		IF lib$ <> "NULL" THEN
			WRITELN type$, "(*", sym$, ")(", token$, ");" TO g_HFILE
			WRITELN "*(", type$, "**) (&", sym$, ") = (", type$,"*)dlsym(__b2c__dlopen__pointer_", ptr$, ", \"", sym$, "\");" TO g_CFILE
			WRITELN "if(", sym$, " == NULL) {if(__b2c__trap){ ERROR = 4; if(!__b2c__catch_set) RUNTIMEERROR(\"IMPORT\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
		ELSE
			WRITELN type$, "(*", alias$, ")(", token$, ");" TO g_HFILE
			WRITELN "*(", type$, "**) (&", alias$, ") = (", type$,"*)dlsym(__b2c__dlopen__pointer_", ptr$, ", \"", sym$, "\");" TO g_CFILE
			WRITELN "if(", alias$, " == NULL) {if(__b2c__trap){ ERROR = 4; if(!__b2c__catch_set) RUNTIMEERROR(\"IMPORT\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
		ENDIF
	END IF

	' Make symbol known to parser
	IF lib$ <> "NULL" THEN
		IF ISTOKEN(g_IMPORTED$, sym$) THEN
			IF g_SEMANTIC = 0 THEN EPRINT NL$, "WARNING: duplicate symbol '", sym$, "' at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		ELSE
			g_IMPORTED$ = APPEND$(g_IMPORTED$, 0, sym$)
		ENDIF
		IF LEN(alias$) THEN WRITELN "#define ", alias$, " ", sym$ TO g_HFILE
	ENDIF

	' Announce runtime error usage
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Normal_Dyn_Array(STRING t$, STRING var$, STRING array$, int is_static, int is_local)

	LOCAL i$, j$, old$, end$, tmp_arr$, idx$, type$, org_type$
	LOCAL nr

	FOR i$ IN var$ STEP ","
		type$ = t$
		g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, CHOP$(i$) & "@" & g_FUNCNAME$)

		' Initialize strings
		IF REGEX(type$, "STRING|char\\*$") OR INSTR(i$, g_STRINGSIGN$) THEN
			IF INSTR(IIF$(TALLY(array$, "("), TOKEN$(array$, 1, "("), array$), ",") THEN
				EPRINT NL$, "Syntax error: string array cannot have more than one dimension line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			END IF
			IF is_local THEN
				WRITELN type$, "* ", i$, ";" TO g_CFILE
				Save_Func_Var(i$, g_FUNCNAME$, type$)
				g_STRINGARGS$ = g_STRINGARGS$ & " long " & CHOP$(i$) & "__b2c_array;"
				Save_Func_Var(CHOP$(i$) & "__b2c_array", g_FUNCNAME$, "long")
				IF NOT(is_static) THEN
					g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__free_str_array_members(&" & CHOP$(i$) & ", " & STR$(g_OPTION_BASE) & ", " & CHOP$(i$) & "__b2c_array);"
					g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & i$
				ENDIF
			ELSE
				WRITELN type$, "* ", i$, ";" TO g_HFILE
				Save_Main_Var(i$, type$)
				WRITELN "long ", CHOP$(i$), "__b2c_array;" TO g_HFILE
				Save_Main_Var(CHOP$(i$) & "__b2c_array", "long")
			END IF
			WRITELN i$, " = (", type$, "*)calloc(", array$, "+", g_OPTION_BASE, ", sizeof(", type$, "));" TO g_CFILE
			WRITELN CHOP$(i$), "__b2c_array = ", array$, ";" TO g_CFILE
			WRITELN "for(__b2c__ctr=0; __b2c__ctr<", array$, "+",  g_OPTION_BASE, "; __b2c__ctr++)", i$, "[__b2c__ctr] = (char*)calloc(1, sizeof(char));" TO g_CFILE
		ELSE
			org_type$ = type$
			' Count elements
			nr = 0
			FOR j$ IN array$ STEP ","
				INCR nr
				type$ = type$ & "*"
			NEXT

			' Declare top most dimension
			IF is_local THEN
				WRITELN type$, " ", i$, ";" TO g_CFILE
				Save_Func_Var(i$, g_FUNCNAME$, org_type$)
				g_STRINGARGS$ = g_STRINGARGS$ & " long " & CHOP$(i$) & "__b2c_array;"
				Save_Func_Var(CHOP$(i$) & "__b2c_array", g_FUNCNAME$, "long")
				IF NOT(is_static) THEN
					g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & CHOP$(i$)
				ELSE
					g_STATICARRAYS$ = g_STATICARRAYS$ & " " & CHOP$(i$) & ":" & STR$(COUNT(type$, 42))
				ENDIF
			ELSE
				WRITELN type$, " ", i$, ";" TO g_HFILE
				Save_Main_Var(i$, org_type$)
				WRITELN "long ", CHOP$(i$), "__b2c_array;" TO g_HFILE
				Save_Main_Var(CHOP$(i$) & "__b2c_array", "long")
			END IF
			WRITELN CHOP$(i$), "__b2c_array = ", TOKEN$(array$, 1, ","), ";" TO g_CFILE
			WRITELN i$, " = (", type$, ")calloc((size_t)", TOKEN$(array$, 1, ","), "+", g_OPTION_BASE, ", sizeof(", LEFT$(type$, LEN(type$)-1), "));" TO g_CFILE

			' Proceed with other dimensions in array
			IF nr > 1 THEN
				old$ = LEFT$(array$, INSTR(array$, ",")-1)
				tmp_arr$ = MID$(array$, INSTR(array$, ",")+1)
				nr = 0
				idx$ = i$
				end$ = ""
				' Construct array initialization
				FOR j$ IN tmp_arr$ STEP ","
					INCR nr
					IF is_local THEN
						g_STRINGARGS$ = g_STRINGARGS$ & " int __b2c_" & CHOP$(i$) & STR$(nr) & ";"
					ELSE
						WRITELN "int __b2c_", CHOP$(i$), nr, ";" TO g_HFILE
					END IF
					idx$ = idx$ & "[__b2c_" & CHOP$(i$) & STR$(nr) & "]"
					WRITELN "for(__b2c_", CHOP$(i$), nr, " = 0; __b2c_", CHOP$(i$), STR$(nr), " < ", old$, "+", g_OPTION_BASE, "; __b2c_", CHOP$(i$), nr, "++){" TO g_CFILE
					type$ = LEFT$(type$, LEN(type$)-1)
					WRITELN idx$, " = (", type$, ")calloc((size_t)", j$, "+", g_OPTION_BASE, ", sizeof(", LEFT$(type$, LEN(type$)-1), "));" TO g_CFILE
					end$ = end$ & " }"
					old$ = j$
				NEXT
				WRITELN end$ TO g_CFILE
				type$ = LEFT$(type$, LEN(type$)-1)

				' De-initialize array members in case of FUNCTION
				IF is_local AND nr > 0 THEN
					nr = 1
					end$ = ""
					FOR j$ IN LEFT$(array$, INSTRREV(array$, ",")-1) STEP ","
						IF NOT(is_static) THEN
							g_STRINGARRAYS$ = g_STRINGARRAYS$ & " for(__b2c_" & CHOP$(i$) & STR$(nr) & " = 0; __b2c_" & CHOP$(i$) & STR$(nr) & " < " & j$ & "+" & STR$(g_OPTION_BASE) & "; __b2c_" & CHOP$(i$) & STR$(nr) & "++){"
							end$ = end$ & " __b2c__STRFREE(" & idx$ & "); }"
							idx$ = LEFT$(idx$, INSTRREV(idx$, "[")-1)
							INCR nr
						END IF
					NEXT
					IF NOT(is_static) THEN
						g_STRINGARRAYS$ = g_STRINGARRAYS$ & " " & end$
					ENDIF
				END IF
			END IF
		END IF
	NEXT

END SUB

'----------------------------------------------------------------------------------------------

SUB Record_Dyn_Array(STRING t$, STRING var$, STRING array$, int is_static)

	LOCAL i$, j$, old$, end$, tmp_arr$, idx$, type$, org_type$
	LOCAL nr

	IF LEN(g_RECORDARRAY$) THEN
		EPRINT NL$, "Syntax error: dynamic array cannot be declared within a dynamic RECORD array at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	FOR i$ IN var$ STEP ","
		type$ = t$
		g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, g_RECORDVAR$ & "." & CHOP$(i$) & "@" & g_FUNCNAME$)

		' Initialize strings
		IF REGEX(type$, "STRING|char\\*$") OR INSTR(i$, g_STRINGSIGN$) THEN
			IF INSTR(IIF$(TALLY(array$, "("), TOKEN$(array$, 1, "("), array$), ",") THEN
				EPRINT NL$, "Syntax error: string array cannot have more than one dimension line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			END IF
			g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & g_RECORDVAR$ & "." & CHOP$(i$) & " = (" & type$ & "*)calloc(" & array$ & "+" & STR$(g_OPTION_BASE) & ", sizeof(" & type$ & "));"
			IF LEN(g_FUNCNAME$) > 0 THEN
				WRITELN type$, "* ", i$, ";" TO g_CFILE
				Save_Func_Var(i$, g_FUNCNAME$, type$)
				WRITELN "long ", CHOP$(i$), "__b2c_array;" TO g_CFILE
				g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & g_RECORDVAR$ & "." & CHOP$(i$) & "__b2c_array = " & array$ & "; for(__b2c__ctr=0; __b2c__ctr<" & array$ & "+" & STR$(g_OPTION_BASE) & "; __b2c__ctr++) " & g_RECORDVAR$ & "." & CHOP$(i$) & "[__b2c__ctr] = (char*)calloc(1, sizeof(char));"
				Save_Func_Var(CHOP$(i$) & "__b2c_array", g_FUNCNAME$, "long")
				IF NOT(is_static) THEN
					g_STRINGARRAYS$ = g_STRINGARRAYS$ & "__b2c__free_str_array_members(&" & g_RECORDVAR$ & "." & CHOP$(i$) & ", " & STR$(g_OPTION_BASE) & ", " & g_RECORDVAR$ & "." & CHOP$(i$) & "__b2c_array);"
					g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & g_RECORDVAR$ & "." & CHOP$(i$)
				ENDIF
			ELSE
				WRITELN type$, "* ", i$, ";" TO g_HFILE
				Save_Main_Var(i$, type$)
				WRITELN "long " & CHOP$(i$), "__b2c_array;" TO g_HFILE
				Save_Main_Var(CHOP$(i$) & "__b2c_array", "long")
				g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & g_RECORDVAR$ & "." & CHOP$(i$) & "__b2c_array = " & array$ & "; for(__b2c__ctr=0; __b2c__ctr<" & array$ & "+" & STR$(g_OPTION_BASE) & "; __b2c__ctr++)" & g_RECORDVAR$ & "." & CHOP$(i$) & "[__b2c__ctr] = (char*)calloc(1, sizeof(char));"
			END IF
		ELSE
			org_type$ = type$
			' Count elements
			nr = 0
			FOR j$ IN array$ STEP ","
				INCR nr
				type$ = type$ & "*"
			NEXT

			' Declare top most dimension
			IF LEN(g_FUNCNAME$) > 0 THEN
				WRITELN type$, " ", i$, ";" TO g_CFILE
				Save_Func_Var(i$, g_FUNCNAME$, org_type$)
				WRITELN "long ", CHOP$(i$), "__b2c_array;" TO g_CFILE
				Save_Func_Var(g_RECORDVAR$ & "." & CHOP$(i$) & "__b2c_array", g_FUNCNAME$, "long")
				IF NOT(is_static) THEN
					g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & g_RECORDVAR$ & "." & CHOP$(i$)
				ELSE
					g_STATICARRAYS$ = g_STATICARRAYS$ & " " & g_RECORDVAR$ & "." & CHOP$(i$) & ":" & STR$(COUNT(type$,42))
				ENDIF
			ELSE
				WRITELN type$, " ", i$, ";" TO g_HFILE
				Save_Main_Var(i$, org_type$)
				WRITELN "long " & CHOP$(i$), "__b2c_array;" TO g_HFILE
				Save_Main_Var(g_RECORDVAR$ & "." & CHOP$(i$) & "__b2c_array", "long")
			END IF
			g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & g_RECORDVAR$ & "." & CHOP$(i$) & "__b2c_array = " & TOKEN$(array$, 1, ",") & ";"
			g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & g_RECORDVAR$ & "." & CHOP$(i$) & " = (" & type$ & ")calloc((size_t)" & TOKEN$(array$, 1, ",") & "+" & STR$(g_OPTION_BASE) & ", sizeof(" & LEFT$(type$, LEN(type$)-1) & "));"

			' Proceed with other dimensions in array
			IF nr > 1 THEN
				old$ = LEFT$(array$, INSTR(array$, ",")-1)
				tmp_arr$ = MID$(array$, INSTR(array$, ",")+1)
				nr = 0
				idx$ = g_RECORDVAR$ & "." & i$
				end$ = ""
				' Construct array initialization
				FOR j$ IN tmp_arr$ STEP ","
					INCR nr
					IF LEN(g_FUNCNAME$) > 0 THEN
						g_STRINGARGS$ = g_STRINGARGS$ & " int __b2c_" & CHOP$(i$) & STR$(nr) & ";"
					ELSE
						g_RECORDEND_HEADER$ = g_RECORDEND_HEADER$ & " int __b2c_" & CHOP$(i$) & STR$(nr) & ";"
					END IF
					idx$ = idx$ & "[__b2c_" & CHOP$(i$) & STR$(nr) & "]"
					g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " for(__b2c_" & CHOP$(i$) & STR$(nr) & " = 0; __b2c_" & CHOP$(i$) & STR$(nr) & " < " & old$ & "+" & STR$(g_OPTION_BASE) & "; __b2c_" & CHOP$(i$) & STR$(nr) & "++){"
					type$ = LEFT$(type$, LEN(type$)-1)
					g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & idx$ & " = (" & type$ & ")calloc((size_t)" & j$ & "+" & STR$(g_OPTION_BASE) & ", sizeof(" & LEFT$(type$, LEN(type$)-1) & "));"
					end$ = end$ & " }"
					old$ = j$
				NEXT
				g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & end$
				type$ = LEFT$(type$, LEN(type$)-1)

				' De-initialize array members in case of FUNCTION
				IF LEN(g_FUNCNAME$) > 0 AND nr > 0 THEN
					nr = 1
					end$ = ""
					FOR j$ IN LEFT$(array$, INSTRREV(array$, ",")-1) STEP ","
						IF NOT(is_static) THEN
							g_STRINGARRAYS$ = g_STRINGARRAYS$ & " for(__b2c_" & CHOP$(i$) & STR$(nr) & " = 0; __b2c_" & CHOP$(i$) & STR$(nr) & " < " & j$ & "+" & STR$(g_OPTION_BASE) & "; __b2c_" & CHOP$(i$) & STR$(nr) & "++){"
							end$ = end$ & " __b2c__STRFREE(" & idx$ & "); }"
							idx$ = LEFT$(idx$, INSTRREV(idx$, "[")-1)
							INCR nr
						END IF
					NEXT
					IF NOT(is_static) THEN
						g_STRINGARRAYS$ = g_STRINGARRAYS$ & " " & end$
					ENDIF
				END IF
			END IF
		END IF
	NEXT

END SUB

'----------------------------------------------------------------------------------------------

SUB Assoc_Array(STRING var$, STRING type$, int by_local)

	LOCAL str$, value$

	FOR str$ IN var$ STEP ","
		value$ = CHOP$(str$)

		' Check if name not already global
		IF LEN(g_FUNCNAME$) AND LEN(Get_Var$("__b2c__assoc_" & value$)) THEN
			EPRINT NL$, "Syntax error: associative array '", value$, "' in LOCAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "' was defined previously!"
			END 1
		ENDIF

		IF by_local THEN
			WRITELN type$, " __b2c__assoc_", value$, "_eval;" TO g_CFILE
			Save_Func_Var("__b2c__assoc_" & value$, g_FUNCNAME$, type$)
			g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__hash_clear(__b2c__assoc_" & value$ & "); free(__b2c__assoc_" & value$ & "); __b2c__assoc_" & value$ & " = NULL;"
		ELSE
			WRITELN type$, " __b2c__assoc_", value$, "_eval;" TO g_HFILE
			Save_Main_Var("__b2c__assoc_" & value$, type$)
		ENDIF
		WRITELN "__b2c__htable *__b2c__assoc_", value$, ", *__b2c__assoc_", value$, "_orig;" TO g_HFILE
		WRITELN "__b2c__assoc_", value$, " = __b2c__hash_new();" TO g_CFILE

		WRITELN type$, " __b2c__assoc_", value$, "_func(const char *key){void *result; result = __b2c__hash_find_value(__b2c__assoc_", value$, ", key);" TO g_HFILE
		IF INSTR(value$, g_STRINGSIGN$) OR REGEX(type$, "STRING|char\\*$") THEN
			WRITELN "if(result == NULL) { return(EmptyString); } return((", type$, ")result); }" TO g_HFILE
		ELSE
			WRITELN "if(result == NULL) { return(0); } return(*(", type$, "*)result); }" TO g_HFILE
		ENDIF
		WRITELN "#define ", value$, "(...) __b2c__assoc_", value$, "_func(__b2c__KEYCOLLECT(__VA_ARGS__))" TO g_HFILE
	NEXT

END SUB

'----------------------------------------------------------------------------------------------

SUB Binary_Tree(STRING var$, STRING type$, int by_local)

	LOCAL str$, value$

	FOR str$ IN var$ STEP ","
		value$ = CHOP$(str$)

		' Check if name not already global
		IF LEN(g_FUNCNAME$) AND LEN(Get_Var$("__b2c__tree_" & value$)) THEN
			EPRINT NL$, "Syntax error: tree variable '", value$, "' in LOCAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "' was defined previously!"
			END 1
		ENDIF
		' Determine binary tree type
		IF REGEX(type$, "STRING|char\\*$") THEN
			type$ = "__b2c__sortstr"
		ELIF INSTR(type$, "double") OR INSTR(type$, "FLOATING") THEN
			type$ = "__b2c__sortnrd"
		ELIF INSTR(type$, "float") THEN
			type$ = "__b2c__sortnrf"
		ELIF INSTR(type$, "long") OR INSTR(type$, "NUMBER") THEN
			type$ = "__b2c__sortnrl"
		ELIF INSTR(type$, "int") THEN
			type$ = "__b2c__sortnri"
		ELIF INSTR(type$, "short") THEN
			type$ = "__b2c__sortnrs"
		ELIF INSTR(type$, "short") THEN
			type$ = "__b2c__sortnrc"
		ELSE
			EPRINT NL$, "Syntax error: unsupported TREE type at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		END IF
		' Declare tree variables
		IF by_local THEN
			WRITELN "void* ", value$, " = NULL;" TO g_CFILE
			Save_Func_Var("__b2c__tree_" & value$, g_FUNCNAME$, type$)
		ELSE
			WRITELN "void* ", value$, " = NULL;" TO g_HFILE
			Save_Main_Var("__b2c__tree_" & value$, type$)
		ENDIF
	NEXT

ENDSUB

'----------------------------------------------------------------------------------------------

SUB Handle_Declare(STRING arg$)

	LOCAL var$, type$, new$, value$, array$, str$
	LOCAL opt

	IF LEN(g_RECORDNAME$) > 0 THEN
		EPRINT NL$, "Syntax error: DECLARE/GLOBAL cannot be used within a RECORD at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	'  Check on a GLOBAL RECORD
	IF ISTOKEN(arg$, "RECORD") THEN
		' Translate to C typedef struct
		g_RECORDNAME$ = "RECORD_" & STR$(g_COUNTER)
		WRITELN "typedef struct {" TO g_HFILE
		g_RECORDVAR$ = MID$(CHOP$(arg$), INSTR(CHOP$(arg$), " ") + 1)
		IF ISTOKEN(g_RECORDVAR$, "ARRAY") THEN
			g_RECORDARRAY$ = MID$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "ARRAY")+5)
			g_RECORDVAR$ = LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "ARRAY")-1) & "[" & g_RECORDARRAY$ & "]"
		ENDIF
		' Store current function name
		IF LEN(g_FUNCNAME$) > 0 THEN
			g_RECORDCACHE$ = g_FUNCNAME$
			g_FUNCNAME$ = ""
		END IF
	ELSE
		' Get the variablename and type
		IF ISTOKEN(arg$, "TYPE") THEN
			var$ = CHOP$(TOKEN$(arg$, 1, "TYPE"))
			type$ = CHOP$(TOKEN$(arg$, 2, "TYPE"))
			IF ISTOKEN(type$, "ARRAY") THEN
				array$ = TOKEN$(type$, 2, "ARRAY")
				type$ = CHOP$(TOKEN$(type$, 1, "ARRAY"))
			ENDIF
		ELIF ISTOKEN(arg$, "ASSOC") THEN
			var$ = CHOP$(TOKEN$(arg$, 1, "ASSOC"))
			type$ = CHOP$(TOKEN$(arg$, 2, "ASSOC"))
		ELIF ISTOKEN(arg$, "TREE") THEN
			var$ = CHOP$(TOKEN$(arg$, 1, "TREE"))
			type$ = CHOP$(TOKEN$(arg$, 2, "TREE"))
		ELSE
			var$ = CHOP$(arg$)
			IF ISTOKEN(var$, "ARRAY") THEN
				array$ = TOKEN$(var$, 2, "ARRAY")
				var$ = TOKEN$(var$, 1, "ARRAY")
			ELIF REGEX(var$, "DIR$|FILE$|short$|int$|long$|float$|double$|char$|void$|STRING$|NUMBER$|FLOATING$") AND NOT(ISTOKEN(var$, "TYPE")) THEN
				EPRINT NL$, "Syntax error: missing TYPE keyword in DECLARE/GLOBAL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			FI
			type$ = IIF$(INSTR(var$, g_STRINGSIGN$), "char*", IIF$(INSTR(var$, g_FLOATSIGN$), "double", g_VARTYPE$))
		END IF

		' Check if variable was already declared
		IF NOT(INSTR(var$, ".")) AND LEFT$(var$, 1) != "(" THEN
			FOR str$ IN EXTRACT$(var$, " ") STEP ","
				' Check for C keywords
				IF REGEX(str$, g_C_KEYWORDS$) THEN
					EPRINT NL$, "Syntax error: variable '", str$, "' in DECLARE/GLOBAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "' is a C keyword or function!"
					END 1
				ENDIF
				' Previous definitions
				IF LEN(Get_Var$(str$, g_FUNCNAME$)) THEN
					EPRINT NL$, "Syntax error: variable '", str$, "' in DECLARE/GLOBAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "' was defined previously!"
					END 1
				ENDIF
			NEXT
		END IF

		' Check for associative array
		IF ISTOKEN(arg$, "ASSOC") THEN
			CALL Assoc_Array(var$, type$, 0)

			' Check for binary tree
		ELIF ISTOKEN(arg$, "TREE") THEN
			CALL Binary_Tree(var$, type$, 0)

			' Check if it is a known type, if not BaCon has to use external .h file
		ELIF NOT(REGEX(EXTRACT$(type$, "*"), "DIR|FILE|short$|int$|long$|float$|double$|char$|void|STRING|NUMBER|FLOATING")) THEN
			IF INSTR(var$, "=") THEN
				WRITELN type$, " ", var$, ";" TO g_HFILE
				Save_Main_Var(var$, type$)
			ELSE
				FOR str$ IN EXTRACT$(var$, " ") STEP ","
					WRITELN type$, " ", str$, ";" TO g_HFILE
					Save_Main_Var(str$, type$)
				NEXT
			ENDIF

			'  Check for dynamic array declaration
		ELIF ISTRUE(LEN(array$)) THEN
			Normal_Dyn_Array(type$, var$, array$, FALSE, FALSE)

			' Check if var is string var
		ELIF ( INSTR(var$, g_STRINGSIGN$) OR REGEX(type$, "STRING|char\\*$") ) AND NOT(INSTR(var$, "=")) THEN
			FOR str$ IN EXTRACT$(var$, " ") STEP ","
				IF NOT(LEN(Get_Var$(str$, g_FUNCNAME$))) THEN
					IF INSTR(str$, "[") THEN
						WRITELN "char *", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { NULL };" TO g_HFILE
						' Save type
						Save_Main_Var(str$, "char*")
					ELIF INSTR(str$, "(") THEN
						' Function pointer
						WRITELN type$, " ", str$, ";" TO g_HFILE
						str$ = LEFT$(str$, INSTRREV(str$, "(")-1)
						Save_Main_Var(EXTRACT$(str$, "[\\(\\*\\)]", TRUE), "void*")
					ELSE
						WRITELN "char *", str$, " = NULL;" TO g_HFILE
						Save_Main_Var(str$, "char*")
					END IF
				END IF
			NEXT
			' Var is string array assignment
		ELIF ( INSTR(var$, g_STRINGSIGN$) OR REGEX(type$, "STRING|char\\*$") ) AND INSTR(var$, "=") THEN
			IF NOT(LEN(Get_Var$(var$, g_FUNCNAME$))) THEN
				IF REGEX(TOKEN$(var$, 1, "="), "\\[.*\\].*") THEN
					WRITELN "char *", LEFT$(var$, INSTR(var$, "[") - 1), "[", STR$(COUNT(var$, 44)+1+g_OPTION_BASE), "] = { NULL };" TO g_HFILE
					' Save type
					Save_Main_Var(var$, "char*")
					' Copy elements
					opt = g_OPTION_BASE
					array$ = MID$(var$, INSTR(var$, "{")+1)
					WHILE LEN(array$)
						str$ = Mini_Parser$(array$)
						WRITELN LEFT$(var$, INSTR(var$, "[")-1), "[", opt, "] = __b2c_Copy_String(", LEFT$(var$, INSTR(var$, "[")-1), "[", opt, "], ", CHOP$(str$, "}", 2), ");" TO g_CFILE
						array$ = MID$(array$, LEN(str$)+2)
						INCR opt
					WEND
				ELSE
					WHILE LEN(var$)
						str$ = Mini_Parser$(var$)
						WRITELN "char *", LEFT$(str$, INSTR(str$, "=")-1), " = NULL;" TO g_HFILE
						WRITELN g_WITHVAR$, LEFT$(str$, INSTR(str$, "=")-1), " = __b2c_Copy_String(", g_WITHVAR$, LEFT$(str$, INSTR(str$, "=")-1), ", ", MID$(str$, INSTR(str$, "=")+1), ");" TO g_CFILE
						Save_Main_Var(LEFT$(str$, INSTR(str$, "=")-1), "char*")
						var$ = MID$(var$, LEN(str$)+2)
					WEND
				ENDIF
			ENDIF

			' Assume char assignment or number
		ELSE
			IF INSTR(var$, "[") AND NOT(INSTR(var$, "=")) THEN
				FOR str$ IN EXTRACT$(var$, " ") STEP ","
					WRITELN type$, " ", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { 0 };" TO g_HFILE
					' Save type
					Save_Main_Var(str$, type$)
				NEXT
			ELIF INSTR(var$, "[") AND INSTR(var$, "=") THEN
				WRITELN type$, " ", MID$(var$, 1, INSTR(var$, "{")) TO g_HFILE
				opt = g_OPTION_BASE
				IF opt > 0 AND COUNT(var$, 91) > 1 THEN EPRINT NL$, "WARNING: OPTION BASE has no impact on multidimensional array '", MID$(var$, 1, INSTR(var$, "[")-1), "' in DECLARE/GLOBAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				WHILE opt > 0 AND COUNT(var$, 91) = 1
					WRITELN " 0, " TO g_HFILE
					DECR opt
				WEND
				WRITELN MID$(var$, INSTR(var$, "{")+1), ";" TO g_HFILE
				' Save type
				Save_Main_Var(var$, type$)
			ELIF INSTR(var$, "(") THEN
				' Function pointer
				WRITELN type$, " ", var$, ";" TO g_HFILE
				var$ = LEFT$(var$, INSTRREV(var$, "(")-1)
				Save_Main_Var(EXTRACT$(var$, "[\\(\\*\\)]", TRUE), "void*")
			ELSE
				FOR str$ IN EXTRACT$(var$, " ") STEP ","
					WRITELN type$, " ", str$, ";" TO g_HFILE
					IF NOT(INSTR(str$, "=")) AND NOT(INSTR(str$, "*")) AND REGEX(type$, "char|short|int|long|double|float|NUMBER|FLOATING") THEN
						WRITELN str$, " = 0;" TO g_CFILE
					ENDIF
					Save_Main_Var(str$, type$)
				NEXT
			END IF
		ENDIF
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Local(STRING arg$)

	LOCAL var$, type$, new$, value$, dim$, dim2$, array$, str$
	LOCAL opt

	' Get the variablename and type
	IF ISTOKEN(arg$, "TYPE") THEN
		var$ = CHOP$(TOKEN$(arg$, 1, "TYPE"))
		type$ = CHOP$(TOKEN$(arg$, 2, "TYPE"))
		IF ISTOKEN(type$, "ARRAY") THEN
			array$ = TOKEN$(type$, 2, "ARRAY")
			type$ = CHOP$(TOKEN$(type$, 1, "ARRAY"))
		ENDIF
	ELIF ISTOKEN(arg$, "ASSOC") THEN
		var$ = CHOP$(TOKEN$(arg$, 1, "ASSOC"))
		type$ = CHOP$(TOKEN$(arg$, 2, "ASSOC"))
	ELIF ISTOKEN(arg$, "TREE") THEN
		var$ = CHOP$(TOKEN$(arg$, 1, "TREE"))
		type$ = CHOP$(TOKEN$(arg$, 2, "TREE"))
	ELSE
		var$ = CHOP$(arg$)
		IF ISTOKEN(var$, "ARRAY") THEN
			array$ = TOKEN$(var$, 2, "ARRAY")
			var$ = TOKEN$(var$, 1, "ARRAY")
		ELIF REGEX(var$, "DIR$|FILE$|short$|int$|long$|float$|double$|char$|void$|STRING$|NUMBER$|FLOATING$") AND NOT(ISTOKEN(var$, "TYPE")) THEN
			EPRINT NL$, "Syntax error: missing TYPE keyword in LOCAL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		FI
		type$ = IIF$(INSTR(var$, g_STRINGSIGN$), "char*", IIF$(INSTR(var$, g_FLOATSIGN$), "double", "long"))
	END IF

	' Check if variable was already declared
	IF NOT(INSTR(var$, ".")) AND LEFT$(var$, 1) != "(" THEN
		FOR str$ IN EXTRACT$(var$, " ") STEP ","
			' Check for C keywords
			IF REGEX(str$, g_C_KEYWORDS$) THEN
				EPRINT NL$, "Syntax error: variable '", str$, "' in LOCAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "' is a C keyword or function!"
				END 1
			ENDIF
			' Previous definitions
			IF LEN(Get_Var$(str$, g_FUNCNAME$)) THEN
				EPRINT NL$, "Syntax error: variable '", str$, "' in LOCAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "' was defined previously!"
				END 1
			ENDIF
		NEXT
	END IF

	' Check for associative array
	IF ISTOKEN(arg$, "ASSOC") THEN
		CALL Assoc_Array(var$, type$, 1)

		' Check for binary tree
	ELIF ISTOKEN(arg$, "TREE") THEN
		CALL Binary_Tree(var$, type$, 1)

		' Check if it is a known type, if not BaCon has to use external .h file
	ELIF NOT(REGEX(EXTRACT$(type$, "*"), "DIR|FILE|short$|int$|long$|float$|double$|char$|void|STRING|NUMBER|FLOATING")) AND NOT(LEN(g_RECORDNAME$)) THEN
		IF INSTR(var$, "=") THEN
			WRITELN type$, " ", var$, ";" TO g_CFILE
			IF LEN(g_FUNCNAME$) THEN
				Save_Func_Var(var$, g_FUNCNAME$, type$)
			ELSE
				Save_Main_Var(var$, type$)
			ENDIF
		ELSE
			FOR str$ IN EXTRACT$(var$, " ") STEP ","
				IF LEN(g_FUNCNAME$) THEN
					WRITELN type$, " ", str$, ";" TO g_CFILE
					Save_Func_Var(str$, g_FUNCNAME$, type$)
				ELSE
					WRITELN type$, " ", str$, ";" TO g_HFILE
					Save_Main_Var(str$, type$)
				ENDIF
			NEXT
		ENDIF

		' Check for dynamic array declaration
	ELIF ISTRUE(LEN(array$)) THEN
		IF LEN(g_RECORDNAME$) > 0 THEN
			IF INSTR(array$, "STATIC") THEN
				Record_Dyn_Array(type$, var$, MID$(array$, 1, INSTR(array$, "STATIC")-1), TRUE)
			ELSE
				Record_Dyn_Array(type$, var$, array$, FALSE)
			FI
		ELSE
			IF INSTR(array$, "STATIC") THEN
				IF LEN(g_FUNCNAME$) THEN
					Normal_Dyn_Array(type$, var$, MID$(array$, 1, INSTR(array$, "STATIC")-1), TRUE, TRUE)
				ELSE
					Normal_Dyn_Array(type$, var$, MID$(array$, 1, INSTR(array$, "STATIC")-1), TRUE, FALSE)
				ENDIF
			ELSE
				IF LEN(g_FUNCNAME$) THEN
					Normal_Dyn_Array(type$, var$, array$, FALSE, TRUE)
				ELSE
					Normal_Dyn_Array(type$, var$, array$, FALSE, FALSE)
				ENDIF
			FI
		END IF

		' Check if var is string var
	ELIF ( REGEX(type$, "STRING|char\\*$") OR INSTR(var$, g_STRINGSIGN$) ) AND NOT(INSTR(var$, "=")) AND NOT(REGEX(type$, ".+\\[.+" & g_STRINGSIGN$ & "\\]")) THEN
		FOR str$ IN EXTRACT$(var$, " ") STEP ","
			IF NOT(LEN(Get_Var$(str$, g_FUNCNAME$))) THEN
				' Check on multidimensional stringarrays
				IF REGEX(str$, "\\[.*\\]\\[") THEN
					EPRINT NL$, "Syntax error: multidimensional stringarrays at line ", g_COUNTER, " in file '", g_CURFILE$, "' are not supported!"
					END 1
				END IF
				' Are we in a function?
				IF ISTRUE(LEN(g_FUNCNAME$)) THEN
					IF ISTRUE(LEN(g_RECORDNAME$)) THEN
						IF REGEX(str$, "\\[.*\\]") THEN
							WRITELN "char *",  REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), ";" TO g_CFILE
							dim$ = MID$(str$, INSTR(str$, "[") + 1)
							IF REGEX(g_RECORDVAR$, "\\[.*\\]") THEN
								IF LEN(g_RECORDARRAY$) THEN
									dim2$ = "__b2c_record_" & EXTRACT$(g_RECORDNAME$, "_TYPE")
								ELSE
									dim2$ = MID$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[") + 1)
								ENDIF
								g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " for(__b2c__counter=0; __b2c__counter<" & LEFT$(dim2$, INSTR(dim2$, "]") - 1) & ";__b2c__counter++) {for(__b2c__ctr=0; __b2c__ctr<" & LEFT$(dim$, INSTR(dim$, "]") - 1) & "; __b2c__ctr++)" & LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1) & "[__b2c__counter]." & LEFT$(str$, INSTR(str$, "[")-1) & "[__b2c__ctr] = NULL;}"
								g_STRINGARRAYS$ = g_STRINGARRAYS$ & " for(__b2c__counter=0; __b2c__counter<" & LEFT$(dim2$, INSTR(dim2$, "]") - 1) & ";__b2c__counter++) {for(__b2c__ctr=0; __b2c__ctr<" & LEFT$(dim$, INSTR(dim$, "]") - 1) & "; __b2c__ctr++) { __b2c__STRFREE(" & LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1) & "[__b2c__counter]." & LEFT$(str$, INSTR(str$, "[")-1) & "[__b2c__ctr]);} }"
							ELSE
								g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " for(__b2c__ctr=0; __b2c__ctr<" & LEFT$(dim$, INSTR(dim$, "]") - 1) & "; __b2c__ctr++)" & g_RECORDVAR$ & "." & LEFT$(str$, INSTR(str$, "[")-1) & "[__b2c__ctr] = NULL;"
								g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__free_str_array_members(&" & TOKEN$(str$, 1, "[") & ", " & STR$(g_OPTION_BASE) & ", " & g_RECORDVAR$ & "." & TOKEN$(dim$, 1, "]") & ");"
							ENDIF
						ELSE
							WRITELN "char *", str$, ";" TO g_CFILE
							' Pointer var should not be initialized
							IF INSTR(str$, g_STRINGSIGN$) AND NOT(REGEX(g_RECORDVAR$, "\\[.*\\]")) AND NOT(LEN(g_RECORDARRAY$)) THEN
								g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & g_RECORDVAR$ & "." & str$ & " = NULL;"
								g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & g_RECORDVAR$ & "." & str$
							ENDIF
						END IF
						Save_Func_Var(str$, g_FUNCNAME$, "char*")
					ELSE
						IF REGEX(str$, "\\[.*\\]") THEN
							WRITELN "char *", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { NULL };" TO g_CFILE
							' Save type
							Save_Func_Var(str$, g_FUNCNAME$, "char*")
							dim$ = MID$(str$, INSTR(str$, "[") + 1)
							g_STRINGARRAYS$ = g_STRINGARRAYS$ & " for(__b2c__ctr=0; __b2c__ctr<" & TOKEN$(dim$, 1, "]") & "; __b2c__ctr++) { __b2c__STRFREE(" & g_WITHVAR$ & TOKEN$(str$, 1, "[") & "[__b2c__ctr]); }"
						ELIF INSTR(str$, "(") THEN
							' Function pointer
							WRITELN type$, " ", str$, ";" TO g_CFILE
							str$ = LEFT$(str$, INSTRREV(str$, "(")-1)
							Save_Func_Var(EXTRACT$(str$, "[\\(\\*\\)]", TRUE), g_FUNCNAME$, "void*")
						ELSE
							WRITELN "char *", str$, " = NULL;" TO g_CFILE
							Save_Func_Var(str$, g_FUNCNAME$, "char*")
							' Defined as string?
							IF INSTR(str$, g_STRINGSIGN$) THEN
								WRITELN str$, " = __b2c_Copy_String(", str$, ", EmptyString);" TO g_CFILE
								g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & str$
							ENDIF
						END IF
					END IF
					' We are in the mainprogram
				ELSE
					IF ISTRUE(LEN(g_RECORDNAME$)) THEN
						IF REGEX(str$, "\\[.*\\]") THEN
							WRITELN "char *", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), ";" TO g_HFILE
						ELSE
							WRITELN "char *", str$, ";" TO g_HFILE
							' Pointer var should not be initialized
							IF INSTR(str$, g_STRINGSIGN$) AND NOT(REGEX(g_RECORDVAR$, "\\[.*\\]")) AND NOT(LEN(g_RECORDARRAY$)) THEN g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " " & g_RECORDVAR$ & "." & CHOP$(str$) & " = NULL;"
						ENDIF
						Save_Main_Var(str$, "char*")
					ELSE
						IF REGEX(str$, "\\[.*\\]") THEN
							WRITELN "char *",  REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { NULL };" TO g_HFILE
							' Save type
							Save_Main_Var(str$, "char*")
						ELIF INSTR(str$, "(") THEN
							' Function pointer
							WRITELN type$, " ", str$, ";" TO g_HFILE
							str$ = LEFT$(str$, INSTRREV(str$, "(")-1)
							Save_Main_Var(EXTRACT$(str$, "[\\(\\*\\)]", TRUE), "void*")
						ELSE
							WRITELN "char *", str$, " = NULL; " TO g_HFILE
							Save_Main_Var(str$, "char*")
						END IF
					END IF
				END IF
			END IF
		NEXT
	ELIF ( INSTR(var$, g_STRINGSIGN$) OR REGEX(type$, "STRING|char\\*") ) AND INSTR(var$, "=") THEN
		IF ISTRUE(LEN(g_FUNCNAME$)) THEN
			IF NOT(LEN(Get_Var$(var$, g_FUNCNAME$))) THEN
				' String array assignment
				IF REGEX(TOKEN$(var$, 1, "="), "\\[.*\\].*") THEN
					WRITELN "static char *", LEFT$(var$, INSTR(var$, "[") - 1), "[", STR$(COUNT(var$, 44)+1+g_OPTION_BASE), "] = { NULL };" TO g_CFILE
					IF LEN(g_RECORDVAR$) THEN
						EPRINT NL$, "Syntax error: C does not allow initialization of an array within a struct at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ENDIF
					' Save type
					Save_Func_Var(var$, g_FUNCNAME$, "char*")
					' Copy elements
					opt = g_OPTION_BASE
					array$ = MID$(var$, INSTR(var$, "{")+1)
					WHILE LEN(array$)
						str$ = Mini_Parser$(array$)
						WRITELN LEFT$(var$, INSTR(var$, "[")-1), "[", opt, "] = __b2c_Copy_String(", LEFT$(var$, INSTR(var$, "[")-1), "[", opt, "], ", CHOP$(str$, "}", 2), ");" TO g_CFILE
						array$ = MID$(array$, LEN(str$)+2)
						INCR opt
					WEND
				ELSE
					WHILE LEN(var$)
						str$ = Mini_Parser$(var$)
						WRITELN "static char *", LEFT$(str$, INSTR(str$, "=")-1), " = NULL;" TO g_CFILE
						WRITELN g_WITHVAR$, LEFT$(str$, INSTR(str$, "=")-1), " = __b2c_Copy_String(", g_WITHVAR$, LEFT$(str$, INSTR(str$, "=")-1), ", ", MID$(str$, INSTR(str$, "=")+1), ");" TO g_CFILE
						Save_Func_Var(LEFT$(str$, INSTR(str$, "=")-1), g_FUNCNAME$, "char*")
						var$ = MID$(var$, LEN(str$)+2)
					WEND
				ENDIF
			ENDIF
		ELSE
			IF NOT(LEN(Get_Var$(var$, g_FUNCNAME$))) THEN
				IF REGEX(TOKEN$(var$, 1, "="), "\\[.*\\].*") THEN
					WRITELN "char *", LEFT$(var$, INSTR(var$, "[") - 1), "[", STR$(COUNT(var$, 44)+1+g_OPTION_BASE), "] = { NULL };" TO g_HFILE
					IF LEN(g_RECORDVAR$) THEN
						EPRINT NL$, "Syntax error: C does not allow initialization of an array within a struct at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ENDIF
					' Save type
					Save_Main_Var(var$, "char*")
					' Copy elements
					opt = g_OPTION_BASE
					array$ = MID$(var$, INSTR(var$, "{")+1)
					WHILE LEN(array$)
						str$ = Mini_Parser$(array$)
						WRITELN LEFT$(var$, INSTR(var$, "[")-1), "[", opt, "] = __b2c_Copy_String(", LEFT$(var$, INSTR(var$, "[")-1), "[", opt, "], ", CHOP$(str$, "}", 2), ");" TO g_CFILE
						array$ = MID$(array$, LEN(str$)+2)
						INCR opt
					WEND
				ELSE
					WHILE LEN(var$)
						str$ = Mini_Parser$(var$)
						WRITELN "char *", LEFT$(str$, INSTR(str$, "=")-1), " = NULL;" TO g_HFILE
						WRITELN g_WITHVAR$, LEFT$(str$, INSTR(str$, "=")-1), " = __b2c_Copy_String(", g_WITHVAR$, LEFT$(str$, INSTR(str$, "=")-1), ", ", MID$(str$, INSTR(str$, "=")+1), ");" TO g_CFILE
						Save_Main_Var(LEFT$(str$, INSTR(str$, "=")-1), "char*")
						var$ = MID$(var$, LEN(str$)+2)
					WEND
				ENDIF
			ENDIF
		END IF
		' Assume number or complicated type
	ELSE
		IF ISTRUE(LEN(g_FUNCNAME$)) THEN
			IF INSTR(var$, "[") AND NOT(INSTR(var$, "=")) THEN
				FOR str$ IN EXTRACT$(var$, " ") STEP ","
					IF NOT(LEN(g_RECORDNAME$)) THEN
						WRITELN type$, " ", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { 0 };" TO g_CFILE
					ELSE
						WRITELN type$, " ", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), ";" TO g_CFILE
					ENDIF
					' Save type
					Save_Func_Var(str$, g_FUNCNAME$, type$)
				NEXT
			ELIF INSTR(var$, "[") AND INSTR(var$, "=") THEN
				' Numeric array assignment
				WRITELN type$, " ", MID$(var$, 1, INSTR(var$, "{")) TO g_CFILE
				opt = g_OPTION_BASE
				IF opt > 0 AND COUNT(var$, 91) > 1 THEN EPRINT NL$, "WARNING: OPTION BASE has no impact on multidimensional array '", MID$(var$, 1, INSTR(var$, "[")-1), "' in LOCAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				WHILE opt > 0 AND COUNT(var$, 91) = 1
					WRITELN " 0, " TO g_CFILE
					DECR opt
				WEND
				WRITELN MID$(var$, INSTR(var$, "{")+1), ";" TO g_CFILE
				IF LEN(g_RECORDVAR$) THEN
					EPRINT NL$, "Syntax error: C does not allow initialization of an array within a struct at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
					END 1
				ENDIF
				' Save type
				Save_Func_Var(var$, g_FUNCNAME$, type$)
			ELIF INSTR(var$, "(") THEN
				' Function pointer
				WRITELN type$, " ", var$, ";" TO g_CFILE
				var$ = LEFT$(var$, INSTRREV(var$, "(")-1)
				Save_Func_Var(EXTRACT$(var$, "[\\(\\*\\)]", TRUE), g_FUNCNAME$, "void*")
			ELSE
				FOR str$ IN EXTRACT$(var$, " ") STEP ","
					WRITELN type$, " ", str$, ";" TO g_CFILE
					IF NOT(INSTR(str$, "=")) AND NOT(INSTR(str$, "*")) AND NOT(LEN(g_RECORDVAR$)) AND REGEX(type$, "char|short|int|long|double|float|NUMBER|FLOATING") THEN
						WRITELN str$, " = 0;" TO g_CFILE
					ENDIF
					Save_Func_Var(str$, g_FUNCNAME$, type$)
				NEXT
			END IF
		ELSE
			IF INSTR(var$, "[") AND NOT(INSTR(var$, "=")) THEN
				FOR str$ IN EXTRACT$(var$, " ") STEP ","
					IF NOT(LEN(g_RECORDNAME$)) THEN
						WRITELN type$, " ", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { 0 };" TO g_HFILE
					ELSE
						WRITELN type$, " ", REPLACE$(str$, "]", "+" & STR$(g_OPTION_BASE) & "]"), ";" TO g_HFILE
					ENDIF
					' Save type
					Save_Main_Var(str$, type$)
				NEXT
			ELIF INSTR(var$, "[") AND INSTR(var$, "=") THEN
				' Numeric array assignment
				WRITELN type$, " ", MID$(var$, 1, INSTR(var$, "{")) TO g_HFILE
				opt = g_OPTION_BASE
				IF opt > 0 AND COUNT(var$, 91) > 1 THEN EPRINT NL$, "WARNING: OPTION BASE has no impact on multidimensional array '", MID$(var$, 1, INSTR(var$, "[")-1), "' in LOCAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				WHILE opt > 0 AND COUNT(var$, 91) = 1
					WRITELN " 0, " TO g_HFILE
					DECR opt
				WEND
				WRITELN MID$(var$, INSTR(var$, "{")+1), ";" TO g_HFILE
				IF LEN(g_RECORDVAR$) THEN
					EPRINT NL$, "Syntax error: C does not allow initialization of an array within a struct at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
					END 1
				ENDIF
				' Save type
				Save_Main_Var(var$, type$)
			ELIF INSTR(var$, "(") THEN
				' Function pointer
				WRITELN type$, " ", var$, ";" TO g_HFILE
				var$ = LEFT$(var$, INSTRREV(var$, "(")-1)
				Save_Main_Var(EXTRACT$(var$, "[\\(\\*\\)]", TRUE), "void*")
			ELSE
				FOR str$ IN EXTRACT$(var$, " ") STEP ","
					WRITELN type$, " ", str$, ";" TO g_HFILE
					IF NOT(INSTR(str$, "=")) AND NOT(INSTR(str$, "*")) AND NOT(LEN(g_RECORDVAR$)) AND REGEX(type$, "char|short|int|long|double|float|NUMBER|FLOATING") THEN
						WRITELN str$, " = 0;" TO g_CFILE
					ENDIF
					Save_Main_Var(str$, type$)
				NEXT
			END IF
		END IF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Read(STRING arg$)

	LOCAL type$, element$, lft$, str$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty READ at at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	FOR element$ IN EXTRACT$(arg$, " ") STEP ","

		' Check if var is string var
		IF REGEX(element$, g_STRINGSIGN$ & "$") THEN
			Register_String(element$)
			type$ = "char*"
		ELSE
			Register_Numeric(element$, FALSE)
			type$ = Get_Var$(element$, g_FUNCNAME$)
		END IF

		' Check type of var, string?
		IF Check_String_Type(element$) THEN
			' Convert to C
			WRITELN "__b2c__assign = __b2c__strdup(__b2c__stringarray[__b2c__stringarray_ptr]); __b2c__stringarray_ptr++;" TO g_CFILE
			Assign_To_String("__b2c__assign", element$, NULL)
		ELSE
			Assign_To_Number("__b2c__floatarray[__b2c__floatarray_ptr]", element$, 0)
			WRITELN "__b2c__floatarray_ptr++;" TO g_CFILE
		END IF
	NEXT

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Endfunction()

	LOCAL line$, tfil$
	LOCAL tmp_HFILE TYPE FILE*

	' Check if we're in a FUNCTION
	IF NOT(LEN(g_FUNCNAME$)) THEN
		EPRINT NL$, "Syntax error: ENDFUNC(TION) outside FUNCTION at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Check if return was found
	IF ISFALSE(LEN(g_FUNCTYPE$)) THEN
		EPRINT NL$, "Syntax error: function '", g_FUNCNAME$, "' was defined without returning a value or string!"
		END 1
	END IF

	' Close the current C file
	CLOSE FILE g_CFILE

	' Put prototype to header file
	IF NOT(INSTR(g_PROTOTYPE$, "::")) THEN WRITELN g_FUNCTYPE$, " ", g_PROTOTYPE$, ";" TO g_HFILE
	g_PROTOTYPE$ = ""

	' Open temporary header file
	tfil$ = MID$(g_CURFILE$, INSTRREV(g_CURFILE$, "/") + 1)
	OPEN g_TEMPDIR$ & "/" & LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h" FOR WRITING AS tmp_HFILE

	' Get original function name
	WRITELN "/* Created with BaCon ", g_VERSION$, " - (c) Peter van Eerten - MIT License */" TO tmp_HFILE
	WRITELN "#undef __b2c__exitval" TO tmp_HFILE
	WRITELN "#define __b2c__exitval 0" TO tmp_HFILE
	IF NOT(INSTR(g_ORIGFUNCNAME$, "(")) THEN
		WRITELN g_FUNCTYPE$, " ", g_FUNCNAME$, "(void) {" TO tmp_HFILE
	ELSE
		WRITELN g_FUNCTYPE$, " ", g_ORIGFUNCNAME$, " {" TO tmp_HFILE
	END IF

	' Add function body
	WRITELN g_STRINGARGS$ TO tmp_HFILE
	OPEN g_CFILE$ FOR READING AS g_CFILE
	WHILE NOT(ENDFILE(g_CFILE)) DO
		READLN line$ FROM g_CFILE
		IF NOT(ENDFILE(g_CFILE)) THEN WRITELN line$ TO tmp_HFILE
	WEND
	CLOSE FILE g_CFILE

	IF g_CATCH_USED = 1 THEN WRITELN "__B2C__PROGRAM__EXIT: ;" TO tmp_HFILE

	' Make sure pointers are always reset
	WRITELN "__b2c__catch_set = __b2c__catch_set_backup;" TO tmp_HFILE

	' Make sure the function always returns something
	IF REGEX(g_FUNCTYPE$, "char\\*$|STRING$") THEN
		WRITELN "return (NULL);}" TO tmp_HFILE
	ELIF REGEX(g_FUNCTYPE$, "char$|short$|int$|long$|double$|float$|NUMBER$|FLOATING$") THEN
		WRITELN "return (0);}" TO tmp_HFILE
	ELSE
		WRITELN "}" TO tmp_HFILE
	ENDIF

	CLOSE FILE tmp_HFILE

	' Include header file
	IF NOT(INSTR(g_INCLUDE_FILES$, LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h")) THEN
		g_INCLUDE_FILES$ = g_INCLUDE_FILES$ & " " & LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h"
	END IF

	' Add to total filelist
	g_TMP_FILES$ = g_TMP_FILES$ & " " & g_TEMPDIR$ & "/" & LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h"

	' Delete temp funcfile
	DELETE FILE g_CFILE$

	' Restore mainfile
	g_CFILE$ = g_COPY_CFILE$
	OPEN g_CFILE$ FOR APPENDING AS g_CFILE

	' Restore CATCH routine
	g_CATCHGOTO$ = g_ORIGCATCHGOTO$
	g_CATCH_USED = g_ORIGCATCH_USED

	' Clear function variables
	g_ORIGFUNCNAME$ = ""
	g_FUNCNAME$ = ""
	g_FUNCTYPE$ = ""
	g_LOCALSTRINGS$ = ""
	g_STRINGARRAYS$ = ""
	g_STRINGARGS$ = ""

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Return(STRING arg$)

	LOCAL type$, str$, name$
	LOCAL x

	arg$ = CHOP$(arg$)

	' Check if we have an argument at all, if not, we return from a GOSUB
	IF ISFALSE(LEN(arg$)) THEN
		WRITELN "if(__b2c__gosub_buffer_ptr >= 0) longjmp(__b2c__gosub_buffer[__b2c__gosub_buffer_ptr], 1);" TO g_CFILE
		EXIT SUB
	END IF

	type$ = IIF$(LEN(g_FUNCTYPE$)>0, g_FUNCTYPE$, Get_Var$(arg$, g_FUNCNAME$))

	' Check type of var, string or normal string?
	IF Check_String_Type(arg$) OR REGEX(g_FUNCTYPE$, "char\\*$|STRING$") OR REGEX(g_FUNCNAME$, g_STRINGSIGN$ & "$") THEN
		' Dynamic array or array created by SPLIT or LOOKUP
		IF ISTOKEN(g_DYNAMICARRAYS$, arg$ & "@" & g_FUNCNAME$) THEN
			g_FUNCTYPE$ = "char**"
			' We return a string
		ELSE
			g_FUNCTYPE$ = "char*"
			WRITELN "__b2c__assign = __b2c__return(", arg$, ");" TO g_CFILE
			arg$ = "__b2c__assign"
		ENDIF

		' Assume variable, check if declared before
	ELIF ISTRUE(LEN(type$)) THEN
		IF INSTR(arg$, "[") THEN
			FOR x = 1 TO COUNT(arg$, 91)
				IF RIGHT$(type$, 1) = "*" THEN type$ = LEFT$(type$, LEN(type$)-1)
			NEXT
		ELSE
			FOR name$ IN g_STATICARRAYS$
				IF INSTR(name$, arg$) THEN
					type$ = type$ & FILL$(VAL(MID$(name$, INSTR(name$, ":")+1)), 42)
					BREAK
				ENDIF
			NEXT
		ENDIF
		g_FUNCTYPE$ = type$

		' Not declared, assume actual value
	ELIF REGEX(arg$, g_LONGSIGN$ & "$") OR REGEX(g_FUNCNAME$, g_LONGSIGN$ & "$") THEN
		g_FUNCTYPE$ = "long"
	ELIF INSTR(arg$, ".") OR REGEX(arg$, g_FLOATSIGN$ & "$") OR REGEX(g_FUNCNAME$, g_FLOATSIGN$ & "$") THEN
		g_FUNCTYPE$ = "double"
	ELSE
		g_FUNCTYPE$ = g_VARTYPE$
	END IF

	' Free strings variables if there are any
	WRITELN g_STRINGARRAYS$ TO g_CFILE
	FOR str$ IN g_LOCALSTRINGS$
		WRITELN "if(", str$, " != NULL) { __b2c__STRFREE(", str$, "); }" TO g_CFILE
	NEXT

	' The actual return value
	WRITELN "__b2c__catch_set = __b2c__catch_set_backup;" TO g_CFILE
	WRITELN "return(", arg$, ");" TO g_CFILE

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Push(STRING arg$)

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty PUSH at at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Store result as string
	WRITELN "__b2c__stack = (char**)realloc(__b2c__stack, (SP+1)*sizeof(char*));" TO g_CFILE
	IF Check_String_Type(arg$) THEN
		WRITELN "__b2c__stack[SP] = __b2c__strdup(", arg$, ");" TO g_CFILE
	ELSE
		WRITELN "__b2c__stack[SP] = calloc(", g_MAX_DIGITS, ", sizeof(char)); snprintf(__b2c__stack[SP], ", g_MAX_DIGITS-1, ", \"%g\", (double)(", arg$, "));" TO g_CFILE
	ENDIF

	' Increase stackpointer
	WRITELN "SP++;" TO g_CFILE

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Pull(STRING arg$)

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty PULL at at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Argument must be a variable
	IF NOT(REGEX(arg$, "[a-zA-Z]+.*")) THEN
		EPRINT NL$, "Syntax error: argument in PULL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "' is not a variable!"
		END 1
	END IF

	' Check if var is string var
	IF REGEX(arg$, g_STRINGSIGN$ & "$") THEN
		Register_String(arg$)
		' Assume number, exclude RECORD elements
	ELSE
		Register_Numeric(arg$, FALSE)
	END IF

	' Decrease stackpointer again
	WRITELN "SP--; if(SP >= 0) {" TO g_CFILE

	' Get the last value from stack
	IF Check_String_Type(arg$) THEN
		Assign_To_String("__b2c__stack[SP]", arg$, NULL)
	ELSE
		Assign_To_Number("__b2c__stack[SP]", arg$, 1)
	END IF
	WRITELN "} else { SP = 0; }" TO g_CFILE

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_SubFunc(STRING arg$)

	LOCAL x, dim, total
	LOCAL dim$, arr$, size$, var$, no_arg$, type$

	' Check argument
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty SUB/FUNCTION at at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Check if we are in a sub already
	IF LEN(g_FUNCNAME$) > 0 THEN
		EPRINT NL$, "Syntax error: cannot define a SUB/FUNCTION within a SUB/FUNCTION at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the functype
	no_arg$ = OUTBETWEEN$(arg$, "(", ")", 1)
	IF ISTOKEN(no_arg$, "TYPE") THEN
		PARSE COLLAPSE$(no_arg$) WITH "* TYPE *" TO match$ SIZE total
		g_FUNCTYPE$ = CHOP$(match$[2])
		arg$ = FIRST$(arg$, 1, "TYPE")
	ENDIF

	' Get the funcname
	IF INSTR(arg$, "(") THEN
		g_ORIGFUNCNAME$ = CHOP$(TOKEN$(arg$, 1, "(")) & "("
		g_PROTOTYPE$ = g_ORIGFUNCNAME$
		g_FUNCNAME$ = CHOP$(TOKEN$(arg$, 1, "("))
	ELSE
		g_ORIGFUNCNAME$ = CHOP$(arg$) & "("
		g_PROTOTYPE$ = g_ORIGFUNCNAME$
		g_FUNCNAME$ = CHOP$(arg$)
	ENDIF

	' In case of C++ classes
	IF INSTR(g_FUNCNAME$, "::") THEN g_FUNCNAME$ = REPLACE$(g_FUNCNAME$, "::", "__")

	' Start miniparser to duplicate string arguments
	IF INSTR(arg$, "(") THEN SPLIT CHOP$(MID$(arg$, INSTR(arg$, "(")), "() ") BY "," TO element$ SIZE dim

	' If there are no arguments to the function at all
	IF dim = 0 THEN
		g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & " void)"
		g_PROTOTYPE$ = g_PROTOTYPE$ & " void)"
	ENDIF

	FOR x = 1 TO dim
		element$[x] = CHOP$(element$[x])
		' Save type
		IF LEFT$(element$[x], 4) = "VAR " THEN
			IF dim > 1 THEN
				EPRINT NL$, "Syntax error: variable argument list cannot be followed by other arguments at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			ELIF INSTR(g_PROTOTYPE$, ",") THEN
				EPRINT NL$, "Syntax error: variable argument list cannot be preceded by other arguments at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			ENDIF
			IF NOT(INSTR(element$[x], " SIZE ")) THEN
				EPRINT NL$, "Syntax error: variable argument list lacks SIZE argument at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			ENDIF
			PARSE COLLAPSE$(element$[x]) WITH "VAR * " & IIF$(ISTOKEN(element$[x], "TYPE"), "TYPE * ") & "SIZE *" TO match$ SIZE total
			arr$ = match$[1]
			IF total = 2 THEN
				type$ = "long"
				size$ = match$[2]
			ELSE
				type$ = match$[2]
				size$ = match$[3]
			ENDIF
			' These are in the function header, and do not exist yet - no need to check with Get_Var
			g_STRINGARGS$ = g_STRINGARGS$ & " long " & size$ & ";"
			Save_Func_Var(size$, g_FUNCNAME$, "long")
			IF Check_String_Type(arr$) OR REGEX(type$, "STRING|char\\*$") THEN
				Save_Func_Var(arr$, g_FUNCNAME$, "char*")
				g_STRINGARGS$ = g_STRINGARGS$ & "long __b2c__var_" & arr$ & " = " & STR$(g_OPTION_BASE) & "; va_list __b2c__ap; char **" & arr$ & " = NULL;" & arr$ & " = (char **)calloc(__b2c__arg_tot+" & STR$(g_OPTION_BASE) & ", sizeof(char*));"
				g_STRINGARGS$ = g_STRINGARGS$ & size$ & " = __b2c__arg_tot; va_start(__b2c__ap, __b2c__arg_tot); while(__b2c__arg_tot)"
				g_STRINGARGS$ = g_STRINGARGS$ & "{" & arr$ & "[__b2c__var_" & arr$ & "] = __b2c__strdup(va_arg(__b2c__ap, char*)); if(" & arr$ & "[__b2c__var_" & arr$ & "] == NULL){" & size$ & " = 0; break; } __b2c__var_" & arr$ & "++; __b2c__arg_tot--; } va_end(__b2c__ap);"
				g_PROTOTYPE$ = "__" & g_PROTOTYPE$ & "int, ..."
				g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & "int __b2c__arg_tot, ..."
				g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__free_str_array_members(&" & arr$ & ", " & STR$(g_OPTION_BASE) & ", " & size$ & "); free(" & arr$ & ");"
				WRITELN "#define ", g_FUNCNAME$, "(...) __", g_FUNCNAME$, "(sizeof((const char*[]) {__VA_ARGS__}) / sizeof(char*), (char*)__VA_ARGS__)" TO g_HFILE
			ELSE
				' The var_args API always uses double when type actually is float. Prevent compile warnings.
				IF INSTR(arr$, g_FLOATSIGN$) OR type$ = "float" THEN type$ = "double"
				Save_Func_Var(arr$, g_FUNCNAME$, type$ & "*")
				g_STRINGARGS$ = g_STRINGARGS$ & "long __b2c__var_" & arr$ & " = " & STR$(g_OPTION_BASE) & "; va_list __b2c__ap; " & type$ & "*" & arr$ & " = NULL;" & arr$ & " = (" & type$ & "*)calloc(__b2c__arg_tot+" & STR$(g_OPTION_BASE) & ", sizeof(" & type$ & "));"
				g_STRINGARGS$ = g_STRINGARGS$ & size$ & " = __b2c__arg_tot; va_start(__b2c__ap, __b2c__arg_tot); while(__b2c__arg_tot)"
				g_STRINGARGS$ = g_STRINGARGS$ & "{" & arr$ & "[__b2c__var_" & arr$ & "] = va_arg(__b2c__ap, " & type$ & "); __b2c__var_" & arr$ & "++; __b2c__arg_tot--; } va_end(__b2c__ap);"
				g_PROTOTYPE$ = "__" & g_PROTOTYPE$ & "int, ..."
				g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & "int __b2c__arg_tot, ..."
				g_STRINGARRAYS$ = g_STRINGARRAYS$ & " free(" & arr$ & ");"
				WRITELN "#define ", g_FUNCNAME$, "(...) __", g_FUNCNAME$, "(sizeof((const " & type$ & "[]) {__VA_ARGS__}) / sizeof(" & type$ & "), (" & type$ & ")__VA_ARGS__)" TO g_HFILE
			ENDIF
			' Add macro in case of VAR argument
			g_ORIGFUNCNAME$ = "__" & g_ORIGFUNCNAME$
		ELIF INSTR(element$[x], "STRING ") OR INSTR(element$[x], "char* ") OR INSTR(element$[x], g_STRINGSIGN$) THEN
			' Add type if it is missing
			IF NOT(INSTR(element$[x], " ")) THEN element$[x] = "char* " & element$[x]
			' Check if already declared
			IF NOT(LEN(Get_Var$(MID$(element$[x], INSTRREV(element$[x], " ")+1), g_FUNCNAME$))) THEN
				Save_Func_Var(MID$(element$[x], INSTRREV(element$[x], " ")+1), g_FUNCNAME$, LEFT$(element$[x], INSTRREV(element$[x], " ")-1))
			ELSE
				IF g_SEMANTIC = 0 THEN EPRINT NL$, "WARNING: variable '", MID$(element$[x], INSTRREV(element$[x], " ")+1), "' in function header at line ", g_COUNTER, " in file '", g_CURFILE$, "' was defined previously!"
			ENDIF
			arr$ = MID$(element$[x], INSTR(element$[x], " ")+1, INSTR(element$[x], "[") - INSTR(element$[x], " ")-1)
			dim$ = MID$(element$[x], INSTR(element$[x], "[")+1, INSTR(element$[x], "]") - INSTR(element$[x], "[")-1)
			IF NOT(INSTR(element$[x], g_STRINGSIGN$)) AND REGEX(element$[x], ".*\\[.*\\].*") THEN
				g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & "char *__b2c_" & arr$ & "[" & dim$ & "+" & STR$(g_OPTION_BASE) &"]"
				g_STRINGARGS$ = g_STRINGARGS$ & " char** " & arr$ & " = __b2c_" & arr$ & ";"
				g_PROTOTYPE$ = g_PROTOTYPE$ & " " & element$[x]
			ELIF NOT(INSTR(element$[x], g_STRINGSIGN$)) THEN
				g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & HEAD$(element$[x], AMOUNT(element$[x])-1) & " __b2c_" & TAIL$(element$[x], 1)
				g_STRINGARGS$ = g_STRINGARGS$ & HEAD$(element$[x], AMOUNT(element$[x])-1) & " " & TAIL$(element$[x], 1) & " = __b2c_" & TAIL$(element$[x], 1) & ";"
				g_PROTOTYPE$ = g_PROTOTYPE$ & " " & element$[x]
			ELIF REGEX(element$[x], ".*\\[.*\\].*") THEN
				IF LEN(dim$) < 1 THEN
					g_ORIGFUNCNAME$ = CHOP$(g_ORIGFUNCNAME$ & " " & element$[x])
					g_PROTOTYPE$ = g_PROTOTYPE$ & " " & element$[x]
				ELSE
					g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & "char *__b2c_" & arr$ & "[" & dim$ & "+" & STR$(g_OPTION_BASE) &"]"
					g_STRINGARGS$ = g_STRINGARGS$ & "char *" & arr$ & "[" & dim$ & "+" & STR$(g_OPTION_BASE) & "] = { NULL };"
					g_STRINGARGS$ = g_STRINGARGS$ & "for(__b2c__ctr=0; __b2c__ctr<" & dim$ & "+" & STR$(g_OPTION_BASE) & "; __b2c__ctr++){if(__b2c_" & arr$ & "[__b2c__ctr]!=NULL) " & arr$ & "[__b2c__ctr] = __b2c__strdup(__b2c_" & arr$ & "[__b2c__ctr]);}"
					g_STRINGARRAYS$ = g_STRINGARRAYS$ & "for(__b2c__ctr=0; __b2c__ctr<" & dim$ & "+" & STR$(g_OPTION_BASE) & "; __b2c__ctr++) { __b2c__STRFREE(" & arr$ & "[__b2c__ctr]); }"
					g_PROTOTYPE$=g_PROTOTYPE$ & "char *__b2c_" & CHOP$(MID$(element$[x], INSTR(element$[x], " ")))
				END IF
			ELSE
				g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & "char *__b2c_" & CHOP$(MID$(element$[x], INSTR(element$[x], " ")))
				var$ = CHOP$(MID$(element$[x], INSTR(element$[x], " ")))
				g_STRINGARGS$ = g_STRINGARGS$ & "char *" & var$ & " = NULL;" & var$ & " = __b2c_Copy_String(" & var$ & ", __b2c_" & var$ & ");"
				g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & CHOP$(MID$(element$[x], INSTR(element$[x], " ")))
				g_PROTOTYPE$ = g_PROTOTYPE$ & " " & element$[x]
			END IF
		ELSE
			' Add type if it is missing
			IF NOT(INSTR(element$[x], " ")) AND NOT(REGEX(element$[x], "^DIR|^FILE|^short|^int|^long|^float|^double|^char|^void|^STRING|^NUMBER|^FLOATING")) THEN
				element$[x] = IIF$(REGEX(element$[x], g_FLOATSIGN$ & "$"), "double ", g_VARTYPE$ & " ") & element$[x]
			ENDIF
			' Check if already declared
			IF NOT(LEN(Get_Var$(MID$(element$[x], INSTRREV(element$[x], " ")+1), g_FUNCNAME$))) THEN
				Save_Func_Var(MID$(element$[x], INSTRREV(element$[x], " ")+1), g_FUNCNAME$, LEFT$(element$[x], INSTRREV(element$[x], " ")-1))
			ELSE
				IF g_SEMANTIC = 0 THEN EPRINT NL$, "WARNING: variable '", MID$(element$[x], INSTRREV(element$[x], " ")+1), "' in function header at line ", g_COUNTER, " in file '", g_CURFILE$, "' was defined previously!"
			ENDIF
			IF REGEX(element$[x], ".*\\[.*\\].*\\].*") THEN
				EPRINT NL$, "Syntax error: cannot pass multidimensional numeric array at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			ELIF REGEX(element$[x], ".*\\[\\].*") THEN
				g_ORIGFUNCNAME$ = CHOP$(g_ORIGFUNCNAME$ & " " & element$[x])
			ELIF REGEX(element$[x], ".*\\[.*\\].*") THEN
				dim$ = MID$(element$[x], INSTR(element$[x], "[")+1, INSTR(element$[x], "]") - INSTR(element$[x], "[")-1)
				arr$ = MID$(element$[x], INSTRREV(element$[x], " ")+1, INSTR(element$[x], "[") - INSTRREV(element$[x], " ")-1)
				g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & TOKEN$(element$[x], 1) & " __b2c_" & arr$ & "[" & dim$ & "+" & STR$(g_OPTION_BASE) & "]"
				g_STRINGARGS$ = g_STRINGARGS$ & TOKEN$(element$[x], 1) & " " & arr$ & "[" & dim$ & "+" & STR$(g_OPTION_BASE) & "] = { 0 };"
				g_STRINGARGS$ = g_STRINGARGS$ & "memmove(" & arr$ & ", __b2c_" & arr$ & ", (" & dim$ & "+" & STR$(g_OPTION_BASE) & ")*sizeof(" & TOKEN$(element$[x], 1) & "));"
			ELSE
				g_ORIGFUNCNAME$ = CHOP$(g_ORIGFUNCNAME$ & " " & element$[x])
			END IF
			g_PROTOTYPE$ = g_PROTOTYPE$ & " " & element$[x]
		END IF
		' Set separation
		IF x < dim THEN
			g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & ","
			g_PROTOTYPE$ = g_PROTOTYPE$ & ","
		ELSE
			g_ORIGFUNCNAME$ = g_ORIGFUNCNAME$ & ")"
			g_PROTOTYPE$ = g_PROTOTYPE$ & ")"
		ENDIF
	NEXT

	' Close the current C file
	CLOSE FILE g_CFILE

	' Make symbol known to parser
	g_IMPORTED$ = g_FUNCNAME$ & " " & g_IMPORTED$

	' Save CATCH routine
	g_ORIGCATCHGOTO$ = g_CATCHGOTO$
	g_ORIGCATCH_USED = g_CATCH_USED
	g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT"
	g_CATCH_USED = 0
	g_STRINGARGS$ = g_STRINGARGS$ & " __b2c__catch_set_backup = __b2c__catch_set; __b2c__catch_set = 0;"

	' Switch to header file
	g_COPY_CFILE$ = g_CFILE$
	g_COPY_COUNTER = g_COUNTER
	g_CFILE$ = LEFT$(g_CFILE$, INSTR(g_CFILE$, ".c")) & g_FUNCNAME$ & ".tmp"

	' Open temp C file
	OPEN g_CFILE$ FOR WRITING AS g_CFILE

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Endsub()

	LOCAL tmp_HFILE TYPE FILE*
	LOCAL line$, element$, tfil$

	' Check if we're in a SUB
	IF NOT(LEN(g_FUNCNAME$)) THEN
		EPRINT NL$, "Syntax error: ENDSUB outside SUB at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Close the current C file
	CLOSE FILE g_CFILE

	' Put prototype to header file
	IF NOT(INSTR(g_PROTOTYPE$, "::")) THEN WRITELN "void ", g_PROTOTYPE$, ";" TO g_HFILE
	g_PROTOTYPE$ = ""

	' Open temporary header file
	tfil$ = MID$(g_CURFILE$, INSTRREV(g_CURFILE$, "/") + 1)
	OPEN g_TEMPDIR$ & "/" & LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h" FOR WRITING AS tmp_HFILE

	' Get original function name
	WRITELN "/* Created with BaCon ", g_VERSION$, " - (c) Peter van Eerten - MIT License */" TO tmp_HFILE
	WRITELN "#undef __b2c__exitval" TO tmp_HFILE
	WRITELN "#define __b2c__exitval" TO tmp_HFILE
	IF INSTR(g_ORIGFUNCNAME$, " (") THEN
		WRITELN "void ", g_ORIGFUNCNAME$, " {" TO tmp_HFILE
	ELIF INSTR(g_ORIGFUNCNAME$, "(") THEN
		WRITELN "void ", g_ORIGFUNCNAME$, " {" TO tmp_HFILE
	ELSE
		WRITELN "void ", g_FUNCNAME$, "(void) {" TO tmp_HFILE
	END IF

	' Finalize sub
	WRITELN g_STRINGARGS$ TO tmp_HFILE
	OPEN g_CFILE$ FOR READING AS g_CFILE
	WHILE NOT(ENDFILE(g_CFILE)) DO
		READLN line$ FROM g_CFILE
		IF NOT(ENDFILE(g_CFILE)) THEN WRITELN line$ TO tmp_HFILE
	WEND
	CLOSE FILE g_CFILE

	' Free strings variables if there are any
	WRITELN g_STRINGARRAYS$ TO tmp_HFILE
	FOR element$ IN g_LOCALSTRINGS$
		IF LEN(element$) > 0 THEN WRITELN "__b2c__STRFREE(", element$, ");" TO tmp_HFILE
	NEXT
	IF g_CATCH_USED = 1 THEN WRITELN "__B2C__PROGRAM__EXIT: ;" TO tmp_HFILE
	WRITELN "__b2c__catch_set = __b2c__catch_set_backup;" TO tmp_HFILE
	WRITELN "}" TO tmp_HFILE

	CLOSE FILE tmp_HFILE

	' Include header file
	IF NOT(INSTR(g_INCLUDE_FILES$, LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h")) THEN
		g_INCLUDE_FILES$ = g_INCLUDE_FILES$ & " " & LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h"
	END IF

	' Add to total filelist
	g_TMP_FILES$ = g_TMP_FILES$ & " " & g_TEMPDIR$ & "/" & LEFT$(tfil$, INSTR(tfil$, ".bac")) & g_FUNCNAME$ & ".h"

	' Delete temp funcfile
	DELETE FILE g_CFILE$

	' Restore mainfile
	g_CFILE$ = g_COPY_CFILE$
	OPEN g_CFILE$ FOR APPENDING AS g_CFILE

	' Restore CATCH routine
	g_CATCHGOTO$ = g_ORIGCATCHGOTO$
	g_CATCH_USED = g_ORIGCATCH_USED

	' Reset variables
	g_ORIGFUNCNAME$ = ""
	g_FUNCNAME$ = ""
	g_LOCALSTRINGS$ = ""
	g_STRINGARRAYS$ = ""
	g_STRINGARGS$ = ""

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Deffn(STRING arg$)

	LOCAL var$, str$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty DEF FN at at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "DEF FN *" TO match$
	var$ = CHOP$(TOKEN$(match$[1], 1, "="))
	str$ = CHOP$(LAST$(match$[1], 1, "="))

	WRITELN "#define ", var$, " (", str$, ")" TO g_HFILE

	' Needed in TOKENIZE to determine amount of intermediate strings
	IF REGEX(TOKEN$(var$, 1, "("), g_STRINGSIGN$ & "$") THEN g_MACRO_STRINGS$(TOKEN$(var$, 1, "(")) = str$

	' Make symbol known to parser
	g_IMPORTED$ = TOKEN$(var$, 1, "(") & " " & g_IMPORTED$

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Const(STRING arg$)

	LOCAL var$, str$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty CONST at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "CONST *" TO match$
	var$ = CHOP$(TOKEN$(match$[1], 1, "="))
	str$ = CHOP$(LAST$(match$[1], 1, "="))

	WRITELN "#define ", var$, " (", str$, ")" TO g_HFILE

	' Needed in TOKENIZE to determine amount of intermediate strings
	IF REGEX(var$, g_STRINGSIGN$ & "$") THEN g_MACRO_STRINGS$(var$) = str$

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Seek(STRING arg$)

	LOCAL descriptor$, offset$, whence$
	LOCAL total

	' Check if OFFSET is available
	IF NOT(ISTOKEN(arg$, "OFFSET")) THEN
		EPRINT NL$, "Syntax error: missing OFFSET in SEEK statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "SEEK * OFFSET * WHENCE *" TO match$ SIZE total
	descriptor$ = match$[1]
	offset$ = match$[2]
	whence$ = IIF$(total > 2, match$[3])

	' Convert to C function
	SELECT whence$
		CASE "START"
			WRITELN "fseek(", descriptor$, ", ", offset$, ", SEEK_SET);" TO g_CFILE
		CASE "CURRENT"
			WRITELN "fseek(", descriptor$, ", ", offset$, ", SEEK_CUR);" TO g_CFILE
		CASE "END"
			WRITELN "fseek(", descriptor$, ", ", offset$, ", SEEK_END);" TO g_CFILE
		DEFAULT
			WRITELN "fseek(", descriptor$, ", ", offset$, ", SEEK_SET);" TO g_CFILE
	ENDSELECT

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Copy(STRING arg$)

	LOCAL from$, to$, size$
	LOCAL total

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in COPY statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "COPY * TO * SIZE *" TO match$ SIZE total
	from$ = match$[1]
	to$ = match$[2]
	size$ = IIF$(total > 2, match$[3])

	' Translate to C function
	IF LEN(size$) = 0 THEN
		WRITELN "if(__b2c__copy(", from$, ", ", to$, ")){ if(__b2c__trap){ ERROR = 2; if(!__b2c__catch_set) RUNTIMEERROR(\"COPY\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, "; } }" TO g_CFILE
	ELSE
		WRITELN "if (__b2c__trap){if(__b2c__memory__check((char*)", to$, ", sizeof(__b2c__MEMTYPE))) {ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"COPY\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
		IF INSTR(from$, g_STRINGSIGN$) THEN
			WRITELN "__b2c__free_str_array_members(&" & to$ & ", " & STR$(g_OPTION_BASE) & ", " & size$ & ");" TO g_CFILE
			WRITELN "if(", from$, "[__b2c__ctr+", g_OPTION_BASE, "]!=NULL) ", to$, "[__b2c__ctr+", g_OPTION_BASE, "]=strdup(", from$, "[__b2c__ctr+", g_OPTION_BASE, "]);}" TO g_CFILE
		ELSE
			WRITELN "memmove((void*)", to$, ", (void*)", from$, ", sizeof(__b2c__MEMTYPE)*", size$, ");" TO g_CFILE
		ENDIF
	FI
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Rename(STRING arg$)

	LOCAL from$, to$

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in RENAME statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the filename and copyname
	PARSE COLLAPSE$(arg$) WITH "RENAME * TO * " TO match$
	from$ = match$[1]
	to$ = match$[2]

	' Translate to C function
	WRITELN "if(rename(", from$, ", ", to$, ") < 0) {if(__b2c__trap){ERROR = 9; if(!__b2c__catch_set) RUNTIMEERROR(\"RENAME\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Color(STRING arg$)

	LOCAL bfg$, col$
	LOCAL total

	' Check syntax
	PARSE COLLAPSE$(arg$) WITH "COLOR * TO *" TO match$ SIZE total

	SELECT match$[1]
		CASE "RESET"
			WRITELN "fputs(\"\\033[0m\", stdout); fflush(stdout);" TO g_CFILE
		CASE "INTENSE"
			WRITELN "fputs(\"\\033[1m\", stdout); fflush(stdout);" TO g_CFILE
		CASE "INVERSE"
			WRITELN "fputs(\"\\033[7m\", stdout); fflush(stdout);" TO g_CFILE
		CASE "NORMAL"
			WRITELN "fputs(\"\\033[22m\", stdout); fflush(stdout);" TO g_CFILE
		DEFAULT
			IF total <= 1 THEN
				EPRINT NL$, "Syntax error: missing TO in COLOR statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			ELSE
				SELECT match$[1]
					CASE "FG"
						bfg$ = "3"
					CASE "BG"
						bfg$ = "4"
					DEFAULT
						IF REGEX(match$[1], "0|1") THEN bfg$ = STR$(VAL(match$[1]) + 3)
						ELSE bfg$ = match$[1]
				END SELECT
				IF ISTOKEN(match$[2], "INTENSE") THEN
					WRITELN "fputs(\"\\033[1m\", stdout); fflush(stdout);" TO g_CFILE
					match$[2] = DEL$(match$[2], ISTOKEN(match$[2], "INTENSE"))
				ENDIF
				IF ISTOKEN(match$[2], "NORMAL") THEN
					WRITELN "fputs(\"\\033[22m\", stdout); fflush(stdout);" TO g_CFILE
					match$[2] = DEL$(match$[2], ISTOKEN(match$[2], "NORMAL"))
				ENDIF
				SELECT match$[2]
					CASE "BLACK"
						col$ = "0"
					CASE "RED"
						col$ = "1"
					CASE "GREEN"
						col$ = "2"
					CASE "YELLOW"
						col$ = "3"
					CASE "BLUE"
						col$ = "4"
					CASE "MAGENTA"
						col$ = "5"
					CASE "CYAN"
						col$ = "6"
					CASE "WHITE"
						col$ = "7"
					DEFAULT
						col$ = match$[2]
				END SELECT
				WRITELN "fprintf(stdout,\"\\033[%ld%ldm\", (long)", bfg$, ", (long)", col$, "); fflush(stdout);" TO g_CFILE
			ENDIF
	ENDSELECT

ENDSUB

'----------------------------------------------------------------------------------------------

SUB Handle_Type(STRING arg$)

	LOCAL type$
	LOCAL offset, cfg

	' Check syntax
	IF NOT(ISTOKEN(arg$, "SET")) AND NOT(ISTOKEN(arg$, "UNSET")) AND NOT(ISTOKEN(arg$, "RESET")) THEN
		EPRINT NL$, "Syntax error: missing SET/UNSET/RESET in TYPE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Check action
	IF ISTOKEN(arg$, "RESET") THEN
		WRITELN "fputs(\"\\033[21m\\033[23m\\033[24m\\033[25m\\033[27m\\033[29m\", stdout); fflush(stdout);" TO g_CFILE
	ELSE
		IF ISTOKEN(arg$, "UNSET") THEN offset = 20
		PARSE COLLAPSE$(arg$) WITH "TYPE " & IIF$(ISTOKEN(arg$, "SET"), "SET", "UNSET") & " *" TO match$
		IF ISTOKEN(match$[1], "BOLD") THEN
			cfg = 1 + offset
			type$ = type$ & "\\033[" & STR$(cfg) & "m"
		ENDIF
		IF ISTOKEN(match$[1], "ITALIC") THEN
			cfg = 3 + offset
			type$ = type$ & "\\033[" & STR$(cfg) & "m"
		ENDIF
		IF ISTOKEN(match$[1], "UNDERLINE") THEN
			cfg = 4 + offset
			type$ = type$ & "\\033[" & STR$(cfg) & "m"
		ENDIF
		IF ISTOKEN(match$[1], "BLINK") THEN
			cfg = 5 + offset
			type$ = type$ & "\\033[" & STR$(cfg) & "m"
		ENDIF
		IF ISTOKEN(match$[1], "INVERSE") THEN
			cfg = 7 + offset
			type$ = type$ & "\\033[" & STR$(cfg) & "m"
		ENDIF
		IF ISTOKEN(match$[1], "STRIKE") THEN
			cfg = 9 + offset
			type$ = type$ & "\\033[" & STR$(cfg) & "m"
		ENDIF
		IF NOT(LEN(type$)) THEN
			EPRINT NL$, "Syntax error: argument in TYPE statement not recognized at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		ENDIF
		WRITELN "fputs(\"", type$, "\", stdout); fflush(stdout);" TO g_CFILE
	ENDIF

ENDSUB

'----------------------------------------------------------------------------------------------

SUB Handle_Gotoxy(STRING arg$)

	LOCAL token$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty GOTOXY at at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Get the target and colorname
	IF INSTR(arg$, ",") THEN
		token$ = Mini_Parser$(arg$)
		arg$ = MID$(arg$, LEN(token$)+2)
	ELSE
		EPRINT NL$, "Syntax error: missing coordinate in GOTOXY at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Translate to C
	WRITELN "fprintf(stdout, \"\\033[%ld;%ldH\",(long)(", CHOP$(arg$), "), (long)(", CHOP$(token$), ")); fflush(stdout);" TO g_CFILE

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Split(STRING arg$)

	LOCAL source$, by$, to$, size$
	LOCAL use_static, total

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in SPLIT statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "STATIC") THEN
		use_static = 1
		arg$ = DEL$(arg$, ISTOKEN(arg$, "STATIC"))
	ENDIF
	IF ISTOKEN(arg$, "BY") THEN
		PARSE COLLAPSE$(arg$) WITH "SPLIT * BY * TO * SIZE *" TO match$
		by$ = match$[2]
		arg$ = APPEND$(HEAD$(arg$, ISTOKEN(arg$, "BY")-1), 0, LAST$(arg$, ISTOKEN(arg$, "TO")-1))
	ELSE
		by$ = "__b2c__option_delim"
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "SPLIT * TO * SIZE *" TO match$ SIZE total
	source$ = match$[1]
	to$ = match$[2]
	size$ = IIF$(total > 2, match$[3])

	' Check type of var, string?
	IF Check_String_Type(to$) = 0 THEN
		EPRINT NL$, "Syntax error: variable ", to$, " in SPLIT statement must be string at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Register numeric
	IF LEN(size$) THEN Register_Numeric(size$, FALSE)

	' Translate to C code
	IF ISTRUE(LEN(g_FUNCNAME$)) THEN
		IF NOT(LEN(Get_Var$(to$, g_FUNCNAME$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			g_STRINGARGS$ = g_STRINGARGS$ & " char **" & to$ & " = NULL; long " & CHOP$(to$) & "__b2c_array = " & STR$(g_OPTION_BASE) & ";"
			Save_Func_Var(to$, g_FUNCNAME$, "char*")
			Save_Func_Var(to$ & "__b2c_array", g_FUNCNAME$, "long")
		END IF
	ELSE
		IF NOT(LEN(Get_Var$(to$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			WRITELN "char **", to$, " = NULL; long ", CHOP$(to$), "__b2c_array = ", g_OPTION_BASE, ";" TO g_HFILE
			Save_Main_Var(to$, "char*")
			Save_Main_Var(to$ & "__b2c_array", "long")
		END IF
	END IF

	' Run the SPLIT code
	IF Check_String_Type(by$) OR by$ = "__b2c__option_delim" THEN
		WRITELN "__b2c__split_by(&", to$, ", ", g_OPTION_BASE, ", &", to$, "__b2c_array, ", source$, ", ", by$, ");" TO g_CFILE
	ELSE
		WRITELN "__b2c__split_with(&", to$, ", ", g_OPTION_BASE, ", &", to$, "__b2c_array, ", source$, ", ", by$, ");" TO g_CFILE
	ENDIF
	IF LEN(size$) THEN WRITELN size$, " = ", to$, "__b2c_array;" TO g_CFILE

	' Add declared array to array list if we are in a function
	IF ISTRUE(LEN(g_FUNCNAME$)) AND NOT(INSTR(g_STRINGARRAYS$, to$)) THEN
		IF NOT(use_static) THEN
			g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__free_str_array_members(&" & to$ & ", " & STR$(g_OPTION_BASE) & ", " & to$ & "__b2c_array);"
			g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & to$
		ENDIF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Join(STRING arg$)

	LOCAL source$, by$, to$, size$, type$
	LOCAL total

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in JOIN statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "BY") THEN
		PARSE COLLAPSE$(arg$) WITH "JOIN * BY * TO * SIZE *" TO match$
		by$ = match$[2]
		arg$ = APPEND$(HEAD$(arg$, ISTOKEN(arg$, "BY")-1), 0, LAST$(arg$, ISTOKEN(arg$, "TO")-1))
	ELSE
		by$ = "EmptyString"
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "JOIN * TO * SIZE *" TO match$ SIZE total
	source$ = match$[1]
	to$ = match$[2]
	size$ = IIF$(total > 2, match$[3])

	' Determine sze if not provided
	IF NOT(LEN(size$)) THEN
		IF ISTOKEN(g_DYNAMICARRAYS$, source$ & "@" & g_FUNCNAME$) THEN
			size$ = source$ & "__b2c_array"
		ELSE
			type$ = Get_Var$(source$, g_FUNCNAME$)
			size$ = "(sizeof(" & source$ & ")/sizeof(" & type$ & ")-" & STR$(g_OPTION_BASE) & ")"
		ENDIF
	ENDIF

	' Check type of var, string?
	IF Check_String_Type(to$) = 0 THEN
		EPRINT NL$, "Syntax error: variable ", to$, " in JOIN statement must be string at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ELSE
		IF REGEX(to$, g_STRINGSIGN$ & "$") THEN
			Register_String(to$)
		END IF
	ENDIF

	' Translate function to C function
	WRITELN "__b2c__join(&__b2c__assign, ", source$, ", ", g_OPTION_BASE, ", ", size$, ", ", by$, ");" TO g_CFILE
	Assign_To_String("__b2c__assign", to$, NULL)

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Sort(STRING arg$)

	LOCAL source$, size$, type$, down$
	LOCAL total

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty SORT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "DOWN") THEN
		down$ = "_down"
		arg$ = DEL$(arg$, ISTOKEN(arg$, "DOWN"))
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "SORT * SIZE *" TO match$ SIZE total
	source$ = match$[1]
	size$ = IIF$(total > 2, match$[2])

	' Determine data type
	type$ = Get_Var$(source$, g_FUNCNAME$)
	IF LEN(type$) THEN
		IF LEN(size$) = 0 THEN
			IF ISTOKEN(g_DYNAMICARRAYS$, source$ & "@" & g_FUNCNAME$) THEN
				size$ = source$ & "__b2c_array"
			ELSE
				size$ = "(sizeof(" & source$ & ")/sizeof(" & type$ & ")-" & STR$(g_OPTION_BASE) & ")"
			ENDIF
		ENDIF
	ELSE
		EPRINT NL$, "Syntax error: unknown array '", source$, "' in SORT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Check DIM size
	WRITELN "if((", size$, "-", g_OPTION_BASE, ") < 0) {if(__b2c__trap){ERROR=36; if(!__b2c__catch_set) RUNTIMEERROR(\"SORT\",", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

	' Determine type
	IF REGEX(source$, g_STRINGSIGN$ & "$") THEN
		WRITELN "qsort(&", source$, "[", g_OPTION_BASE, "], ", size$, ", sizeof(char*), __b2c__sortstr", down$, ");" TO g_CFILE
	ELIF INSTR(type$, "double") OR INSTR(type$, "FLOATING") THEN
		WRITELN "qsort(&", source$, "[", g_OPTION_BASE, "], ", size$, ", sizeof(double), __b2c__sortnrd", down$, ");" TO g_CFILE
	ELIF INSTR(type$, "float") THEN
		WRITELN "qsort(&", source$, "[", g_OPTION_BASE, "], ", size$, ", sizeof(float), __b2c__sortnrf", down$, ");" TO g_CFILE
	ELIF INSTR(type$, "long") OR INSTR(type$, "NUMBER") THEN
		WRITELN "qsort(&", source$, "[", g_OPTION_BASE, "], ", size$, ", sizeof(long), __b2c__sortnrl", down$, ");" TO g_CFILE
	ELIF INSTR(type$, "int") THEN
		WRITELN "qsort(&", source$, "[", g_OPTION_BASE, "], ", size$, ", sizeof(int), __b2c__sortnri", down$, ");" TO g_CFILE
	ELIF INSTR(type$, "short") THEN
		WRITELN "qsort(&", source$, "[", g_OPTION_BASE, "], ", size$, ", sizeof(short), __b2c__sortnrs", down$, ");" TO g_CFILE
	ELIF INSTR(type$, "short") THEN
		WRITELN "qsort(&", source$, "[", g_OPTION_BASE, "], ", size$, ", sizeof(char), __b2c__sortnrc", down$, ");" TO g_CFILE
	ELSE
		EPRINT NL$, "Syntax error: unsupported array type in SORT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Alias(STRING arg$)

	LOCAL var$, to$

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in ALIAS statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "ALIAS * TO *" TO match$
	var$ = match$[1]
	to$ = match$[2]

	' Translate to C
	WRITELN "#define ", EXTRACT$(to$, CHR$(34)), " ", EXTRACT$(var$, CHR$(34)) TO g_HFILE
	g_IMPORTED$ = to$ & " " & g_IMPORTED$

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Lookup(STRING arg$)

	LOCAL source$, to$, size$, sort$, down$, type$
	LOCAL total, use_sort, use_static

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in LOOKUP statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF MATCH(COLLAPSE$(arg$), "* SORT *") THEN
		use_sort = 1
		arg$ = DEL$(arg$, ISTOKEN(arg$, "SORT"))
	ENDIF
	IF ISTOKEN(arg$, "DOWN") THEN
		down$ = "_down"
		arg$ = DEL$(arg$, ISTOKEN(arg$, "DOWN"))
	ENDIF
	IF ISTOKEN(arg$, "STATIC") THEN
		use_static = 1
		arg$ = DEL$(arg$, ISTOKEN(arg$, "STATIC"))
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "LOOKUP * TO * SIZE *" TO match$ SIZE total
	source$ = match$[1]
	to$ = match$[2]
	size$ = IIF$(total > 2, match$[3])

	' Check type of var, string?
	IF Check_String_Type(to$) = 0 THEN
		EPRINT NL$, "Syntax error: variable ", to$, " in LOOKUP statement must be string at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Register numeric var
	IF LEN(size$) THEN
		Register_Numeric(size$, FALSE)
		WRITELN size$, " = 0;" TO g_CFILE
	END IF

	' Translate to C code
	IF ISTRUE(LEN(g_FUNCNAME$)) THEN
		IF NOT(LEN(Get_Var$(to$, g_FUNCNAME$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			g_STRINGARGS$ = g_STRINGARGS$ & " char **" & to$ & " = { NULL }; long " & to$ & "__b2c_array = " & STR$(g_OPTION_BASE) & ";"
			Save_Func_Var(to$, g_FUNCNAME$, "char*")
			Save_Func_Var(to$ & "__b2c_array", g_FUNCNAME$, "long")
		END IF
	ELSE
		IF NOT(LEN(Get_Var$(to$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			WRITELN "char **", to$, " = { NULL }; long ", to$, "__b2c_array = ", g_OPTION_BASE, ";" TO g_HFILE
			Save_Main_Var(to$, "char*")
			Save_Main_Var(to$ & "__b2c_array", "long")
		END IF
	END IF

	' Run the LOOKUP code
	IF NOT(use_sort) THEN
		WRITELN to$, "__b2c_array = __b2c__lookup_by_order(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ");" TO g_CFILE
	ELSE
		type$ = Get_Var$("__b2c__assoc_" & source$, g_FUNCNAME$)
		IF REGEX(type$, "char\\*|STRING") THEN
			WRITELN to$, "__b2c_array = __b2c__lookup_by_sort(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ", 0, __b2c__sortstr", down$, ");" TO g_CFILE
		ELIF REGEX(type$, "double|FLOATING") THEN
			WRITELN to$, "__b2c_array = __b2c__lookup_by_sort(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ", 1, __b2c__sortnrd_wrap", down$, ");" TO g_CFILE
		ELIF REGEX(type$, "float") THEN
			WRITELN to$, "__b2c_array = __b2c__lookup_by_sort(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ", 2, __b2c__sortnrf_wrap", down$, ");" TO g_CFILE
		ELIF REGEX(type$, "long|NUMBER") THEN
			WRITELN to$, "__b2c_array = __b2c__lookup_by_sort(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ", 3, __b2c__sortnrl_wrap", down$, ");" TO g_CFILE
		ELIF REGEX(type$, "int") THEN
			WRITELN to$, "__b2c_array = __b2c__lookup_by_sort(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ", 4, __b2c__sortnri_wrap", down$, ");" TO g_CFILE
		ELIF REGEX(type$, "short") THEN
			WRITELN to$, "__b2c_array = __b2c__lookup_by_sort(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ", 5, __b2c__sortnrs_wrap", down$, ");" TO g_CFILE
		ELIF REGEX(type$, "char") THEN
			WRITELN to$, "__b2c_array = __b2c__lookup_by_sort(__b2c__assoc_", source$, ", &", to$, ", ", to$, "__b2c_array, ", g_OPTION_BASE, ", 6, __b2c__sortnrc_wrap", down$, ");" TO g_CFILE
		ELSE
			EPRINT NL$, "Syntax error: unsupported array type in LOOKUP at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		END IF
	ENDIF
	IF LEN(size$) THEN WRITELN size$, " = ", to$, "__b2c_array;" TO g_CFILE

	' Add declared array to array list if we are in a function
	IF ISTRUE(LEN(g_FUNCNAME$)) AND NOT(INSTR(g_STRINGARRAYS$, to$ & "__b2c_array")) THEN
		IF NOT(use_static) THEN
			g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__free_str_array_members(&" & to$ & ", " & STR$(g_OPTION_BASE) & ", " & to$ & "__b2c_array);"
			g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & to$
		ENDIF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Relate(STRING arg$)

	LOCAL source$, to$, str$

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in RELATE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	to$ = LAST$(arg$, ISTOKEN(arg$, "TO"))
	arg$ = HEAD$(arg$, ISTOKEN(arg$, "TO")-1)
	source$ = CHOP$(arg$)

	' Check if declared as ASSOC
	IF NOT(LEN(Get_Var$("__b2c__assoc_" & source$))) AND NOT(LEN(Get_Var$("__b2c__assoc_" & source$, g_FUNCNAME$))) THEN
		EPRINT NL$, "Syntax error: variable '", source$, "' not declared as ASSOC in RELATE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Assign relations
	FOR str$ IN EXTRACT$(to$, " ") STEP ","
		IF NOT(LEN(Get_Var$("__b2c__assoc_" & str$))) AND NOT(LEN(Get_Var$("__b2c__assoc_" & str$, g_FUNCNAME$))) THEN
			EPRINT NL$, "Syntax error: variable '", str$, "' not declared as ASSOC in RELATE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		END IF
		g_RELATE$[g_RELATE_CTR] = source$ & " " & str$
		INCR g_RELATE_CTR
	NEXT

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Data(STRING arg$)

	LOCAL token$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty DATA at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Start miniparser
	WHILE LEN(arg$)
		token$ = Mini_Parser$(arg$)
		IF INSTR(token$, CHR$(34)) THEN
			WRITELN CHOP$(token$), ", "; TO STRINGARRAYFILE
			INCR g_CCTR
		ELSE
			WRITELN CHOP$(token$), ", "; TO FLOATARRAYFILE
			INCR g_FCTR
		END IF
		arg$ = MID$(arg$, LEN(token$)+2)
	WEND

	' Align properly
	IF INSTR(token$, CHR$(34)) THEN
		WRITELN "" TO STRINGARRAYFILE
	ELSE
		WRITELN "" TO FLOATARRAYFILE
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Redim(STRING arg$)

	LOCAL type$, var$, to$

	' Check if TO is available
	IF NOT(INSTR(arg$, " TO ")) THEN
		EPRINT NL$, "Syntax error: missing TO in REDIM statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the source string
	var$ = CHOP$(LEFT$(arg$, INSTR(arg$, " TO ") - 1))
	to$ = CHOP$(MID$(arg$, INSTR(arg$, " TO ") + 4))

	type$ = CHOP$(Get_Var$(var$, g_FUNCNAME$))
	IF NOT(LEN(type$)) AND NOT(Check_String_Type(var$)) THEN
		EPRINT NL$, "Syntax error: cannot REDIM array which is not declared previously at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Delete old data from strings if new size is smaller
	IF Check_String_Type(var$) THEN
		WRITELN "if(", to$, "<", var$, "__b2c_array) {for(__b2c__ctr=", to$, "; __b2c__ctr<", var$, "__b2c_array; __b2c__ctr++) {__b2c__STRFREE(", var$, "[__b2c__ctr+", g_OPTION_BASE, "]);} }" TO g_CFILE
		type$ = "char*"
	END IF

	' Realloc
	WRITELN var$, " = (", type$, "*)realloc(", var$, ", (", to$, "+", g_OPTION_BASE, ")*sizeof(", type$, "));" TO g_CFILE

	' Re-initialize records if new area is bigger
	IF REGEX(type$, "_type$") OR REGEX(type$, "_TYPE$") THEN
		WRITELN "if(__b2c_record_", MID$(var$, INSTR(var$, ".")+1), " < ", to$, ") { for(__b2c__ctr=__b2c_record_", MID$(var$, INSTR(var$, ".")+1), "+", g_OPTION_BASE, "; __b2c__ctr<", to$, "+", g_OPTION_BASE, "; __b2c__ctr++) memset(&", var$, "[__b2c__ctr], 0, sizeof(", type$, "));}" TO g_CFILE
		WRITELN "__b2c_record_", MID$(var$, INSTR(var$, ".")+1), " = ", to$, ";" TO g_CFILE
	ELSE
		' Re-initialize strings if new area is bigger
		IF Check_String_Type(var$) THEN
			WRITELN "if(", to$, ">", var$, "__b2c_array) {for(__b2c__ctr=", var$, "__b2c_array; __b2c__ctr<", to$, "; __b2c__ctr++) ", var$, "[__b2c__ctr+", g_OPTION_BASE, "] = (char*)calloc(1, sizeof(char));}" TO g_CFILE
		END IF
		WRITELN var$, "__b2c_array = ", to$, ";" TO g_CFILE
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Swap(STRING arg$)

	LOCAL var$, to$, type$, tmp$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty SWAP at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Get the source string
	var$ = CHOP$(LEFT$(arg$, INSTR(arg$, ",") - 1))
	to$ = CHOP$(MID$(arg$, INSTR(arg$, ",") + 1))

	' Perform universal swap
	IF Check_String_Type(var$) AND NOT(Check_String_Type(to$)) THEN
		WRITELN "__b2c__assign = calloc(", g_MAX_DIGITS, "+1, sizeof(char)); if (floor(", to$, ") == ", to$, ") { __b2c__ctr = snprintf(__b2c__assign, ", g_MAX_DIGITS, ", \"%ld\", (long) ", to$, "); }" TO g_CFILE
		WRITELN "else { __b2c__ctr = snprintf (__b2c__assign, ", g_MAX_DIGITS, ", \"%g\", (double) ", to$, "); } ", to$, " = VAL(", var$, "); __b2c__STRFREE(", var$, "); ", var$, " = __b2c__assign;" TO g_CFILE
	ELIF NOT(Check_String_Type(var$)) AND Check_String_Type(to$) THEN
		WRITELN "__b2c__assign = calloc(", g_MAX_DIGITS, "+1, sizeof(char)); if (floor(", var$, ") == ", var$, ") { __b2c__ctr = snprintf(__b2c__assign, ", g_MAX_DIGITS, ", \"%ld\", (long) ", var$, "); }" TO g_CFILE
		WRITELN "else { __b2c__ctr = snprintf (__b2c__assign, ", g_MAX_DIGITS, ", \"%g\", (double) ", var$, "); } ", var$, " = VAL(", to$, "); __b2c__STRFREE(", to$, "); ", to$, " = __b2c__assign;" TO g_CFILE
	ELSE
		' Determine type
		IF Check_String_Type(var$) THEN
			type$ = "char *"
		ELSE
			type$ = Get_Var$(var$, g_FUNCNAME$)
			IF LEN(type$) = 0 THEN
				EPRINT NL$, "Syntax error: cannot determine type of variables in SWAP at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
				END 1
			END IF
			' Leave one dimension out to exchange array variables
			type$ = LEFT$(type$, INSTR(type$, "*")-1)
		END IF

		' Get rid of array syntax
		tmp$ = IIF$(INSTR(var$, "["), LEFT$(var$, INSTR(var$, "[")-1), var$)

		' Declare temp variable
		IF LEN(g_FUNCNAME$) > 0 THEN
			IF NOT(LEN(Get_Var$("__b2c__" & tmp$ & "_swap", g_FUNCNAME$))) THEN
				g_STRINGARGS$ = g_STRINGARGS$ & " " & type$ & " __b2c__" & tmp$ & "_swap;"
				Save_Func_Var("__b2c__" & tmp$ & "_swap", g_FUNCNAME$, type$)
			ENDIF
		ELSE
			IF NOT(LEN(Get_Var$("__b2c__" & tmp$ & "_swap"))) THEN
				WRITELN type$, " __b2c__", tmp$, "_swap;" TO g_HFILE
				Save_Main_Var("__b2c__" & tmp$ & "_swap", type$)
			ENDIF
		ENDIF
		WRITELN "__b2c__", tmp$, "_swap = ", var$, "; ", var$, " = ", to$, "; ", to$, " = __b2c__", tmp$, "_swap;" TO g_CFILE
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Setserial(STRING arg$)

	LOCAL desc$, value$, param$ = "0", not$ = "0"
	LOCAL which

	' Check if a mode is available
	IF NOT(REGEX(arg$, " IMODE | OMODE | CMODE | LMODE | OTHER | SPEED ")) THEN
		EPRINT NL$, "Syntax error: no mode specified in SETSERIAL statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	desc$ = LEFT$(arg$, INSTR(arg$, " "))

	' Get the setting
	IF INSTR(arg$, " OTHER ") THEN
		value$ = MID$(arg$, INSTRREV(arg$, "OTHER ")+6)
	ELIF INSTR(arg$, " SPEED ") THEN
		value$ = MID$(arg$, INSTRREV(arg$, "SPEED ")+6)
	ELSE
		value$ = MID$(arg$, INSTRREV(arg$, "MODE ")+5)
	ENDIF

	IF INSTR(arg$, "IMODE") THEN
		which = 0
	ELIF INSTR(arg$, "OMODE") THEN
		which = 1
	ELIF INSTR(arg$, "CMODE") THEN
		which = 2
	ELIF INSTR(arg$, "LMODE") THEN
		which = 3
	ELIF INSTR(arg$, "OTHER") THEN
		which = 4
		param$ = TOKEN$(value$, 1, "=")
		value$ = TOKEN$(value$, 2, "=")
	ELIF INSTR(arg$, "SPEED") THEN
		which = 5
	END IF

	IF INSTR(value$, "~") THEN not$ = "1"

	WRITELN "ERROR = __b2c_setserial(", desc$, ", ", which, ", ", param$, ", ", value$, ", ", not$, ");" TO g_CFILE
	WRITELN "if(ERROR && __b2c__trap){ if(!__b2c__catch_set) RUNTIMEERROR(\"SETSERIAL\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, "; }" TO g_CFILE

	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Call(STRING arg$)

	LOCAL var$, lft$, str$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty CALL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Make sure to set function syntax
	IF NOT(REGEX(TOKEN$(arg$, 1, " TO "), "\\(.*\\)")) THEN
		IF INSTR(arg$, " TO ") THEN
			arg$ = TOKEN$(arg$, 1, " TO ") & "() TO " & TOKEN$(arg$, 2, " TO ")
		ELSE
			arg$ = arg$ & "()"
		ENDIF
	ENDIF

	' Just call, no assignment
	IF NOT(INSTR(arg$, " TO ")) THEN
		WRITELN arg$, ";" TO g_CFILE
	ELSE
		var$ = CHOP$(TOKEN$(arg$, 2, " TO "))
		' Check if var is string var
		IF REGEX(var$, g_STRINGSIGN$ & "$") THEN
			Register_String(var$)
			' Assume number, exclude RECORD elements
		ELSE
			Register_Numeric(var$, FALSE)
		END IF

		' Check type of var, string?
		IF Check_String_Type(var$) THEN
			WRITELN "__b2c__assign = (char*)__b2c__strdup(", TOKEN$(arg$, 1, " TO "), ");" TO g_CFILE
			WRITELN "if(__b2c__assign == NULL) { __b2c__assign = (char*)calloc(1, sizeof(char)); }" TO g_CFILE
			Assign_To_String("__b2c__assign", var$, NULL)
		ELSE
			Assign_To_Number(TOKEN$(arg$, 1, " TO "), var$, 0)
		END IF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Run(STRING arg$)

	LOCAL escaped, in_string, x
	LOCAL token$

	' Check if we have an argument at all
	IF AMOUNT(arg$) = 1 THEN
		EPRINT NL$, "Syntax error: empty RUN at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF
	arg$ = LAST$(arg$, 1)

	' Start miniparser to find separate arguments
	FOR x = 2 TO LEN(arg$)-2
		SELECT ASC(MID$(arg$, x, 1))
			CASE 92
				IF escaped THEN
					escaped = FALSE
				ELSE
					escaped = TRUE
				FI
			CASE 34
				IF escaped THEN in_string = NOT(in_string)
				escaped = FALSE
			CASE 32
				IF ISFALSE(in_string) THEN arg$ = LEFT$(arg$, x-1) & CHR$(34) & "," & CHR$(34) & MID$(arg$, x+1)
				escaped = FALSE
			DEFAULT
				escaped = FALSE
		END SELECT
	NEXT

	' Get first token
	token$ = Mini_Parser$(arg$)

	WRITELN "execlp(", token$, "," & EXTRACT$(arg$, "\\" & CHR$(34)) & ", NULL); fflush(stdout);" TO g_CFILE

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Save(type, arg$)

	LOCAL var$, to$, size$

	' Check syntax
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: SAVE/BSAVE/APPEND/BAPPEND without TO at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Get the arguments
	IF ISTOKEN(arg$, "SIZE") THEN
		size$ = LAST$(arg$, ISTOKEN(arg$, "SIZE"))
		arg$ = HEAD$(arg$, ISTOKEN(arg$, "SIZE")-1)
	ELSE
		size$ = "0"
	ENDIF
	to$ = LAST$(arg$, ISTOKEN(arg$, "TO"))
	arg$ = HEAD$(arg$, ISTOKEN(arg$, "TO")-1)
	var$ = CHOP$(arg$)

	' How to open the file
	WRITELN "ERROR = __b2c__save(", type, ", ", size$, ", ", to$, ", ", var$, ", NULL);" TO g_CFILE
	WRITELN "if(ERROR && __b2c__trap) { if(!__b2c__catch_set) RUNTIMEERROR(\"SAVE/BSAVE/APPEND/BAPPEND\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, "; }" TO g_CFILE
	IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Map(STRING arg$)

	LOCAL source$, by$, to$, size$, type$, i$
	LOCAL use_static, total

	' Check if BY is available
	IF NOT(ISTOKEN(arg$, "BY")) THEN
		EPRINT NL$, "Syntax error: missing BY in MAP statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in MAP statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "STATIC") THEN
		use_static = 1
		arg$ = DEL$(arg$, ISTOKEN(arg$, "STATIC"))
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "MAP * BY * TO * SIZE *" TO match$ SIZE total
	source$ = match$[1]
	by$ = match$[2]
	to$ = match$[3]
	size$ = IIF$(total > 3, match$[4])

	' Determine sze if not provided
	IF NOT(LEN(size$)) THEN
		IF ISTOKEN(g_DYNAMICARRAYS$, CHOP$(TOKEN$(source$, 1, ",")) & "@" & g_FUNCNAME$) THEN
			size$ = CHOP$(TOKEN$(source$, 1, ",")) & "__b2c_array"
		ELSE
			type$ = Get_Var$(CHOP$(TOKEN$(source$, 1, ",")), g_FUNCNAME$)
			size$ = "(sizeof(" & CHOP$(TOKEN$(source$, 1, ",")) & ")/sizeof(" & type$ & ")-" & STR$(g_OPTION_BASE) & ")"
		ENDIF
	ENDIF

	' Remove doublequotes from BY
	by$ = EXTRACT$(by$, CHR$(34))

	' Make sure to get the type right
	type$ = "long"

	IF Check_String_Type(by$) THEN
		type$ = "char*"
	ELSE
		FOR i$ IN source$
			IF REGEX(Get_Var$(i$, g_FUNCNAME$), ".*double.*|.*FLOATING.*") THEN
				type$ = "double"
				BREAK
			ENDIF
		NEXT
	ENDIF

	' Declare target array
	IF NOT(LEN(Get_Var$(to$, g_FUNCNAME$))) THEN
		IF g_OPTION_EXPLICIT$ = "1" OR g_OPTION_EXPLICIT$ = "TRUE" THEN
			EPRINT NL$, "Syntax error: OPTION EXPLICIT forces explicit variable declaration at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		ENDIF
		IF ISTRUE(LEN(g_FUNCNAME$)) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			WRITELN type$ , "* ", to$, "; long ", to$, "__b2c_array;" TO g_CFILE
			Save_Func_Var(to$, g_FUNCNAME$, type$ & "*")
			Save_Func_Var(to$ & "__b2c_array", g_FUNCNAME$, "long")
		ELSE
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			WRITELN type$ , "* ", to$, "; long ", to$, "__b2c_array;" TO g_HFILE
			Save_Main_Var(to$, type$ & "*")
			Save_Main_Var(to$ & "__b2c_array", "long")
		END IF
		WRITELN to$, " = (", type$, "*)calloc((size_t)(", size$, "+", g_OPTION_BASE, "), sizeof(", type$, "));" TO g_CFILE
		WRITELN to$, "__b2c_array = ", size$, ";" TO g_CFILE

		' Cleanup local array members
		IF use_static = 0 THEN
			IF type$ = "char*" THEN
				g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__free_str_array_members(&" & to$ & ", " & STR$(g_OPTION_BASE) & ", " & size$ & ");"
			ENDIF
			g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & to$
		ENDIF
	END IF

	' Create the C code
	WRITELN "for(__b2c__ctr=", g_OPTION_BASE, "; __b2c__ctr<", size$, "+", g_OPTION_BASE, "; __b2c__ctr++){" TO g_CFILE
	IF type$ = "char*" THEN
		WRITELN to$, "[__b2c__ctr] = __b2c_Copy_String(", to$, "[__b2c__ctr], ", by$, "(", REPLACE$(source$, ",", "[__b2c__ctr],"), "[__b2c__ctr])); }" TO g_CFILE
	ELSE
		WRITELN to$, "[__b2c__ctr] = ", by$, "(", REPLACE$(source$, ",", "[__b2c__ctr],"), "[__b2c__ctr]); }" TO g_CFILE
	ENDIF

ENDSUB

'----------------------------------------------------------------------------------------------

SUB Handle_Tree(STRING arg$)

	LOCAL tree$, node$, type$, func$
	LOCAL total

	' Check if NODE is available
	IF NOT(ISTOKEN(arg$, "NODE")) THEN
		EPRINT NL$, "Syntax error: missing NODE in TREE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	PARSE COLLAPSE$(arg$) WITH "TREE * NODE * TYPE *" TO match$ SIZE total
	tree$ = match$[1]
	node$ = match$[2]
	type$ = IIF$(total > 2, match$[3])

	func$ = Get_Var$("__b2c__tree_" & tree$, g_FUNCNAME$)
	IF LEN(type$) THEN
		WRITELN "__b2c__treenr((void*)__b2c__MEMDUP(sizeof(", type$, "), ", node$, "), &", tree$, ", ", func$, ");" TO g_CFILE
	ELSE
		IF func$ = "__b2c__sortnrd" THEN
			type$ = "double"
		ELIF func$ = "__b2c__sortnrf" THEN
			type$ = "float"
		ELIF func$ = "__b2c__sortnrl" THEN
			type$ = "long"
		ELIF func$ = "__b2c__sortnri" THEN
			type$ = "int"
		ELIF func$ = "__b2c__sortnrs" THEN
			type$ = "short"
		ELIF func$ = "__b2c__sortnrc" THEN
			type$ = "char"
		ENDIF
		IF func$ = "__b2c__sortstr" THEN
			WRITELN "__b2c__assign = __b2c__strdup(", node$, "); __b2c__treestr((void*)__b2c__MEMDUP(sizeof(char*), __b2c__assign), __b2c__assign, &", tree$, ", ", func$, ");" TO g_CFILE
		ELSE
			WRITELN "__b2c__assign = (char*)", node$, "; __b2c__treenr((void*)__b2c__MEMDUP(sizeof(", type$, "), __b2c__assign), &", tree$, ", ", func$, ");" TO g_CFILE
		ENDIF
	ENDIF

END SUB

'----------------------------------------------------------------------------------------------

SUB Handle_Collect(STRING arg$)

	LOCAL source$, to$, size$, sort$, type$
	LOCAL total, use_static

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in COLLECT statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	END IF

	' Get the arguments
	IF ISTOKEN(arg$, "STATIC") THEN
		use_static = 1
		arg$ = DEL$(arg$, ISTOKEN(arg$, "STATIC"))
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "COLLECT * TO * SIZE *" TO match$ SIZE total
	source$ = match$[1]
	to$ = match$[2]
	size$ = IIF$(total > 2, match$[3])

	' Register numeric var
	IF LEN(size$) THEN
		Register_Numeric(size$, FALSE)
		WRITELN size$, " = 0;" TO g_CFILE
	END IF

	' Translate to C code
	IF ISTRUE(LEN(g_FUNCNAME$)) THEN
		IF NOT(LEN(Get_Var$(to$, g_FUNCNAME$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			g_STRINGARGS$ = g_STRINGARGS$ & " void **" & to$ & " = { NULL }; long " & to$ & "__b2c_array = " & STR$(g_OPTION_BASE) & ";"
			Save_Func_Var(to$, g_FUNCNAME$, "void*")
			Save_Func_Var(to$ & "__b2c_array", g_FUNCNAME$, "long")
		END IF
	ELSE
		IF NOT(LEN(Get_Var$(to$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			WRITELN "void **", to$, " = { NULL }; long ", to$, "__b2c_array = ", g_OPTION_BASE, ";" TO g_HFILE
			Save_Main_Var(to$, "void*")
			Save_Main_Var(to$ & "__b2c_array", "long")
		END IF
	END IF

	' Run the COLLECT code
	WRITELN to$, "__b2c_array = __b2c__collect(", source$, ", &", to$, ", ", g_OPTION_BASE, ");" TO g_CFILE
	IF LEN(size$) THEN WRITELN size$, " = ", to$, "__b2c_array;" TO g_CFILE

	' Add declared array to array list if we are in a function
	IF ISTRUE(LEN(g_FUNCNAME$)) AND NOT(INSTR(g_STRINGARRAYS$, to$ & "__b2c_array")) THEN
		IF NOT(use_static) THEN
			g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & to$
		ENDIF
	END IF

ENDSUB

'----------------------------------------------------------------------------------------------

SUB Handle_Parse(STRING arg$)

	LOCAL source$, to$, with$, size$, by$ = "__b2c__option_delim"
	LOCAL use_static, total

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "WITH")) THEN
		EPRINT NL$, "Syntax error: missing WITH in PARSE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Check if TO is available
	IF NOT(ISTOKEN(arg$, "TO")) THEN
		EPRINT NL$, "Syntax error: missing TO in PARSE statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Get the arguments
	IF ISTOKEN(arg$, "STATIC") THEN
		use_static = 1
		arg$ = DEL$(arg$, ISTOKEN(arg$, "STATIC"))
	ENDIF
	IF ISTOKEN(arg$, "BY") THEN
		PARSE COLLAPSE$(arg$) WITH "PARSE * WITH * BY * TO * SIZE *" TO match$
		by$ = match$[3]
		arg$ = APPEND$(HEAD$(arg$, ISTOKEN(arg$, "BY")-1), 0, LAST$(arg$, ISTOKEN(arg$, "TO")-1))
	ENDIF
	PARSE COLLAPSE$(arg$) WITH "PARSE * WITH * TO * SIZE *" TO match$ SIZE total
	source$ = match$[1]
	with$ = match$[2]
	to$ = match$[3]
	size$ = IIF$(total > 3, match$[4])

	' Check type of var, string?
	IF Check_String_Type(to$) = 0 THEN
		EPRINT NL$, "Syntax error: variable ", to$, " in PARSE statement must be string at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
		END 1
	ENDIF

	' Register numeric
	IF LEN(size$) THEN Register_Numeric(size$, FALSE)

	' Translate to C code
	IF ISTRUE(LEN(g_FUNCNAME$)) THEN
		IF NOT(LEN(Get_Var$(to$, g_FUNCNAME$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			g_STRINGARGS$ = g_STRINGARGS$ & " char **" & to$ & " = NULL; long " & CHOP$(to$) & "__b2c_array = " & STR$(g_OPTION_BASE) & ";"
			Save_Func_Var(to$, g_FUNCNAME$, "char*")
			Save_Func_Var(to$ & "__b2c_array", g_FUNCNAME$, "long")
		END IF
	ELSE
		IF NOT(LEN(Get_Var$(to$))) THEN
			g_DYNAMICARRAYS$ = APPEND$(g_DYNAMICARRAYS$, 0, to$ & "@" & g_FUNCNAME$)
			WRITELN "char **", to$, " = NULL; long ", CHOP$(to$), "__b2c_array = ", g_OPTION_BASE, ";" TO g_HFILE
			Save_Main_Var(to$, "char*")
			Save_Main_Var(to$ & "__b2c_array", "long")
		END IF
	END IF

	' Run the PARSE code
	WRITELN "__b2c__parse(&", to$, ", ", g_OPTION_BASE, ", &", to$, "__b2c_array, ", source$, ", ", with$, ",", by$, ");" TO g_CFILE

	IF LEN(size$) THEN WRITELN size$, " = ", to$, "__b2c_array;" TO g_CFILE

	' Add declared array to array list if we are in a function
	IF ISTRUE(LEN(g_FUNCNAME$)) AND NOT(INSTR(g_STRINGARRAYS$, to$)) THEN
		IF NOT(use_static) THEN
			g_STRINGARRAYS$ = g_STRINGARRAYS$ & " __b2c__free_str_array_members(&" & to$ & ", " & STR$(g_OPTION_BASE) & ", " & to$ & "__b2c_array);"
			g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & to$
		ENDIF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

SUB guiGenerate(data$)

	LOCAL widget$, type$, name$, parent$, callback$, uid$, resource$, icon$, map$, func$, prop$, arg$
	LOCAL gui TYPE FILE*

	g_TMP_FILES$ = g_TMP_FILES$ & " " & g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".gui.h"

	OPEN g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".gui.h" FOR WRITING AS gui
	IF g_WHICH_GUI = 2 THEN
		WRITELN "void* __b2c__cld = NULL; struct __b2c__cdk{ void *addr; char *name; }; struct __b2c__cdk *__b2c__cdknames = { NULL }; int __b2c__cdknr = 0;" TO gui
		WRITELN "void *__b2c_get_by_name(uintptr_t id, char *name) { void *result = NULL; int x; for(x=0; x<__b2c__cdknr; x++){ if(!strcmp(name, __b2c__cdknames[x].name)) { result = __b2c__cdknames[x].addr; break; } } return(result); }" TO gui
		WRITELN "static int __b2c_cdk_callback(EObjectType cdktype GCC_UNUSED, void *object, void *clientData, chtype key GCC_UNUSED) { __b2c__cld = clientData; return(TRUE); }" TO gui
		WRITELN "char *__b2c__guiExecute(uintptr_t id, int type) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; unsigned long len; int key; boolean function; CDKOBJS *obj; CDKSCREEN *screen; screen = (CDKSCREEN*)id; __b2c__cld = NULL; refreshCDKScreen(screen);" TO gui
		WRITELN "while(__b2c__cld == NULL) { obj = getCDKFocusCurrent(screen); if(obj != NULL) { key = getchCDKObject(obj, &function); traverseCDKOnce(screen, obj, key, function, NULL); } } len = strlen((char *) __b2c__cld); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO gui
		WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+1); memmove(buf[idx], __b2c__cld, len); __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO gui
		WRITELN "uintptr_t __b2c__guiDefine(void){ atexit(endCDK);" TO gui
	ELIF g_WHICH_GUI = 1 OR g_WHICH_GUI = 3 THEN
		WRITELN "gpointer __b2c__cld = NULL; gpointer __b2c__cad = NULL;" TO gui
		WRITELN "GtkWidget *__b2c_get_by_name(uintptr_t id, char *name) { GList *widget, *x; widget = (GList*)id; for(x = widget; x != NULL; x = x->next) { if(!strcmp(name, gtk_widget_get_name(GTK_WIDGET(x->data)))) { break; } } if(x==NULL) { return(NULL); } else { return(x->data); } }" TO gui
		WRITELN "void __b2c_gtk_callback(gpointer client_data, uintptr_t call_data, GtkWidget *w) { size_t size; __b2c__cld = client_data;" TO gui
		WRITELN "if(call_data) {if( (sizeof(call_data)>sizeof(gint) ? call_data>>(sizeof(gint)*8) : 0) == 0 && (gint)call_data < 0 && (gint)call_data > -16) { __b2c__cad = realloc(__b2c__cad, sizeof(gint)); (*(gint*)__b2c__cad) = (gint)call_data; } else" TO gui
		IF g_WHICH_GUI = 1 THEN
			WRITELN "{ switch(((GdkEventAny*)call_data)->type) { case GDK_BUTTON_PRESS: size = sizeof(GdkEventButton); break; case GDK_2BUTTON_PRESS: size = sizeof(GdkEventButton); break; case GDK_3BUTTON_PRESS: size = sizeof(GdkEventButton); break;" TO gui
			WRITELN "case GDK_BUTTON_RELEASE: size = sizeof(GdkEventButton); break; case GDK_EXPOSE: size = sizeof(GdkEventExpose); break; case GDK_DAMAGE: size = sizeof(GdkEventExpose); break; case GDK_ENTER_NOTIFY: size = sizeof(GdkEventCrossing); break;" TO gui
			WRITELN "case GDK_LEAVE_NOTIFY: size = sizeof(GdkEventCrossing); break; case GDK_FOCUS_CHANGE: size = sizeof(GdkEventFocus); break; case GDK_CONFIGURE: size = sizeof(GdkEventConfigure); break; case GDK_PROPERTY_NOTIFY: size = sizeof(GdkEventProperty); break;" TO gui
			WRITELN "case GDK_SCROLL: size = sizeof(GdkEventScroll); break; case GDK_KEY_PRESS: size = sizeof(GdkEventKey); break; case GDK_KEY_RELEASE: size = sizeof(GdkEventKey); break; case GDK_SETTING: size = sizeof(GdkEventSetting); break;" TO gui
			WRITELN "default: size = sizeof(GdkEventAny); } __b2c__cad = realloc(__b2c__cad, size); memcpy(__b2c__cad, (void*)call_data, size); } } }" TO gui
		ELSE
			WRITELN "{ size = sizeof(void*); __b2c__cad = realloc(__b2c__cad, size); memcpy(__b2c__cad, (void*)call_data, size); } } }" TO gui
		ENDIF
		WRITELN "char *__b2c__guiExecute(uintptr_t id, int type) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; GList *widget; const char *name = NULL; unsigned long len, total = 0; widget=(GList*)id; __b2c__cld = NULL;" TO gui
		WRITELN "GTKWIDGETSHOW(widget->data); while(1) { GTKMAINITERATION; if(__b2c__cld) { break; } } len = strlen((char*)__b2c__cld); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+1); memmove(buf[idx], __b2c__cld, len);" TO gui
		WRITELN "if(type == 1) { total += len; buf[idx] = (char*)__b2c_str_realloc(buf[idx], total+1+", g_MAX_DIGITS, "+1); len = snprintf(buf[idx]+total, ", g_MAX_DIGITS, ", \" %p\", __b2c__cad); }" TO gui
		WRITELN "total += len; __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO gui
		WRITELN "uintptr_t __b2c__guiDefine(void){ GList *widget_list = NULL; GTKINIT;" TO gui
	ELSE
		WRITELN "Widget __b2c__CallbackedWidget; XtPointer __b2c__cld = NULL; XtPointer __b2c__cad = NULL; Atom __b2c_wm_delete_window = 0;" TO gui
		WRITELN "int __b2c_xt_close(Display *dpy) { XtCloseDisplay(dpy); exit(EXIT_SUCCESS); }" TO gui
		WRITELN "static void __b2c_wm_delete(Widget w, XEvent *event, String *params, Cardinal *num_params)" TO gui
		WRITELN "{ if(event->type == ClientMessage && event->xclient.data.l[0] == __b2c_wm_delete_window) { __b2c__CallbackedWidget = w; __b2c__cld = params[0]; } }" TO gui
		WRITELN "void __b2c_xt_callback(Widget w, XtPointer client_data, XtPointer call_data)" TO gui
		WRITELN "{ __b2c__CallbackedWidget = w; if(client_data) { __b2c__cld = client_data; } if(call_data) { __b2c__cad = calloc(1, sizeof(XtPointer)); memcpy(__b2c__cad, call_data, sizeof(XtPointer)); } }" TO gui
		WRITELN "char *__b2c__guiExecute(uintptr_t id, int type) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char *name; unsigned long len, total = 0; __b2c__CallbackedWidget = NULL; if(__b2c__cad) { free(__b2c__cad); } __b2c__cad = NULL; __b2c__cld = NULL;" TO gui
		WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } XtRealizeWidget((Widget)id); if(__b2c_wm_delete_window) { XSetWMProtocols(XtDisplay((Widget)id), XtWindow((Widget)id), &__b2c_wm_delete_window, 1); }" TO gui
		WRITELN "while(1) { XtAppProcessEvent(XtWidgetToApplicationContext((Widget)id), XtIMAll); if(__b2c__CallbackedWidget) { break; } } if(__b2c__cld) { len = strlen(__b2c__cld); buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+1); memmove(buf[idx], __b2c__cld, len); }" TO gui
		WRITELN "else { name = XtName(__b2c__CallbackedWidget); if(name == NULL) { return(NULL); } len = strlen(name); buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+1); memmove(buf[idx], name, len); } if(type == 1) { total += len;" TO gui
		WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], total+1+", g_MAX_DIGITS, "+1); len = snprintf(buf[idx]+total, ", g_MAX_DIGITS, ", \" %p\", __b2c__cad); }" TO gui
		WRITELN "total += len; __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO gui
		WRITELN "uintptr_t __b2c__guiDefine(void){XtAppContext app; Display *dpy; Screen *scr; Arg args[32]; int n = 0, argc = 1; char *argv[1];" TO gui
	ENDIF
	WHILE LEN(data$) > 2
		widget$ = FLATTEN$(INBETWEEN$(data$, "{" , "}"))
		data$ = CHOP$(OUTBETWEEN$(data$, "{", "}"))
		type$ = "" : name$ = "" : parent$ = "" : callback$ = "" : prop$ = "," : arg$ = ""
		FOR item$ IN widget$
			item$ = REPLACE$(CHOP$(item$), "\\$$", g_STRINGSIGN$, TRUE)
			SELECT TOKEN$(item$, 1, "=")
				CASE "type"
					type$ = TOKEN$(item$, 2, "=")
					IF (g_WHICH_GUI = 1 OR g_WHICH_GUI = 3) AND NOT(INSTR(type$, "_TYPE_")) THEN type$ = "GTK_TYPE_" & UCASE$(type$)
				CASE "name"
					name$ = TOKEN$(item$, 2, "=")
				CASE "parent"
					parent$ = TOKEN$(item$, 2, "=")
				CASE "callback"
					callback$ = APPEND$(callback$, 0, TOKEN$(item$, 2, "="))
				CASE "map"
					map$ = APPEND$(map$, 0, TOKEN$(item$, 2, "="))
				CASE "uid"
					uid$ = APPEND$(uid$, 0, TOKEN$(item$, 2, "="))
				CASE "resources"
					resource$ = TOKEN$(item$, 2, "=")
				CASE "args"
					arg$ = TOKEN$(item$, 2, "=")
					arg$ = REPLACE$(CHOP$(arg$), "$", g_STRINGSIGN$)
				DEFAULT
					IF g_WHICH_GUI = 1 OR g_WHICH_GUI = 3 THEN
						prop$ = prop$ & CHR$(34) & TOKEN$(item$, 1, "=") & CHR$(34) & "," & TOKEN$(item$, 2, "=") & ","
					ELSE
						WRITELN "XtSetArg(args[n], ", DELIM$(item$, "=", ","), "); n++;" TO gui
					ENDIF
			ENDSELECT
		NEXT
		IF LEN(name$) = 0 THEN
			EPRINT NL$, "Syntax error: widget does not have a name at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		ENDIF
		IF LEN(type$) = 0 THEN
			EPRINT NL$, "Syntax error: widget does not have a type at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
			END 1
		ENDIF
		IF g_WHICH_GUI = 2 THEN
			IF LCASE$(type$) = "window" THEN
				WRITELN "CDKSCREEN *" & name$ & ", *__main_window;" TO gui
				WRITELN name$, " = initCDKScreen(initscr()); initCDKColor(); __main_window = ", name$, ";" TO gui
			ELSE
				WRITELN "CDK", UCASE$(type$), " *", name$, ";" TO gui
				WRITELN name$, " = newCDK", PROPER$(type$), "(", arg$, ");" TO gui
			ENDIF
			WRITELN "__b2c__cdknames = realloc(__b2c__cdknames, sizeof(struct __b2c__cdk)*(__b2c__cdknr+1));" TO gui
			WRITELN "__b2c__cdknames[__b2c__cdknr].name = __b2c__strdup(\"", name$, "\"); __b2c__cdknames[__b2c__cdknr].addr = ", name$, "; __b2c__cdknr++;" TO gui
			IF LEN(callback$) THEN
				FOR item$ IN callback$
					IF HASDELIM(item$, ",") THEN
						WRITELN "bindCDKObject(v", UCASE$(type$), ", ", name$, ", ", TOKEN$(item$, 1, ","), ", __b2c_cdk_callback, \"", TOKEN$(item$, 2, ","), "\");" TO gui
					ELSE
						WRITELN "bindCDKObject(v", UCASE$(type$), ", ", name$, ", ", TOKEN$(item$, 1, ","), ", __b2c_cdk_callback, \"", name$, "\");" TO gui
					ENDIF
				NEXT
			ENDIF
		ELIF g_WHICH_GUI = 1 OR g_WHICH_GUI = 3 THEN
			WRITELN "GtkWidget *", name$, ";" TO gui
			WRITELN name$, "= GTK_WIDGET(g_object_new(" & type$ & " " & prop$ & " NULL));" TO gui
			IF type$ = "GTK_TYPE_WINDOW" OR INSTR(type$, "DIALOG") THEN WRITELN "gtk_window_set_icon_name(GTK_WINDOW(" & name$ & "), \"bacon\");" TO gui
			WRITELN "gtk_widget_set_name(" & name$ & ", \"" & name$ & "\");" TO gui
			WRITELN "widget_list = g_list_append(widget_list, ", name$, ");" TO gui
			IF LEN(parent$) THEN
				IF type$ = "GTK_TYPE_MENU" OR type$ = "GTK_TYPE_MENU_ITEM" THEN
					WRITELN "gtk_menu_shell_append(GTK_MENU_SHELL(" & parent$ & "), " & name$ & ");" TO gui
				ELSE
					WRITELN "GTKCONTAINERADD(" & parent$ & ", " & name$ & ");" TO gui
				ENDIF
			ENDIF
			IF LEN(callback$) THEN
				FOR item$ IN callback$
					IF HASDELIM(item$, ",") THEN
						WRITELN "g_signal_connect_swapped(G_OBJECT(", name$, "), \"", TOKEN$(item$, 1, ","), "\", G_CALLBACK(__b2c_gtk_callback), \"", TOKEN$(item$, 2, ","), "\");" TO gui
					ELSE
						WRITELN "g_signal_connect_swapped(G_OBJECT(", name$, "), \"", TOKEN$(item$, 1, ","), "\", G_CALLBACK(__b2c_gtk_callback), \"", name$, "\");" TO gui
					ENDIF
				NEXT
			ENDIF
		ELSE
			WRITELN "Widget ", name$, ";" TO gui
			IF type$ = "window" THEN
				WRITELN "Widget __main_window; Dimension w, h;" TO gui
				IF LEN(callback$) THEN WRITELN "XtActionsRec actions[1];" TO gui
				WRITELN "XtSetLanguageProc(NULL, NULL, NULL);" TO gui
				WRITELN "argv[0] = calloc(1, sizeof(char));" TO gui
				IF FILEEXISTS("/usr/local/share/pixmaps/BaCon.xbm") THEN
					icon$ = "/usr/local/share/pixmaps/BaCon.xbm"
				ELIF FILEEXISTS("/usr/share/pixmaps/BaCon.xbm") THEN
					icon$ = "/usr/share/pixmaps/BaCon.xbm"
				ELSE
					icon$ = "xlogo32"
				ENDIF
				IF LEN(resource$) THEN
					WRITELN "String resources[] = { \"*iconPixmap:" & icon$ & "\", ", resource$, ", NULL };" TO gui
				ELSE
					WRITELN "String resources[] = { \"*iconPixmap:" & icon$ & "\", NULL };" TO gui
				ENDIF
				WRITELN name$, " = XtOpenApplication(&app, \"BaConGUI\", NULL, 0, &argc, argv, resources, sessionShellWidgetClass, args, n);" TO gui
				WRITELN "dpy = XtDisplay(", name$, ");" TO gui
				WRITELN "scr = XtScreen(", name$, ");" TO gui
				WRITELN "XtVaGetValues(", name$, ", XtNwidth, &w, XtNheight, &h, NULL);" TO gui
				WRITELN "XtVaSetValues(", name$, ", XtNx, WidthOfScreen(scr)/2-(w/2), XtNy, HeightOfScreen(scr)/2-(h/2), NULL);" TO gui
				IF LEN(callback$) THEN
					WRITELN "__b2c_wm_delete_window = XInternAtom(dpy, \"WM_DELETE_WINDOW\", False);" TO gui
					WRITELN "actions[0].string = \"__b2c_wm_delete\"; actions[0].proc = __b2c_wm_delete;" TO gui
					WRITELN "XtAppAddActions(app, actions, XtNumber(actions));" TO gui
					WRITELN "XtOverrideTranslations(", name$, ", XtParseTranslationTable(\"<Message>WM_PROTOCOLS: __b2c_wm_delete(", callback$, ")\"));" TO gui
					WRITELN "#ifndef __b2c__gui_xaw" TO gui
					WRITELN "XtVaSetValues(", name$, ", XmNdeleteResponse, XmDO_NOTHING, NULL);" TO gui
					WRITELN "#endif" TO gui
				ENDIF
				WRITELN "__main_window = ", name$, ";" TO gui
				WRITELN "XSetIOErrorHandler(__b2c_xt_close);" TO gui
				WRITELN "#ifdef __b2c__gui_uil" TO gui
				WRITELN "MrmHierarchy hierarchy;" TO gui
				WRITELN "MrmType class_code;" TO gui
				WRITELN "Widget main_object;" TO gui
				WRITELN "static MrmRegisterArg callback_list[] = {" TO gui
				IF LEN(map$) THEN
					FOR item$ IN map$
						FOR func$ IN item$ STEP ","
							WRITELN "{ \"", func$, "\", (XtPointer)__b2c_xt_callback }," TO gui
						NEXT
					NEXT
				ELSE
					WRITELN " NULL " TO gui
				ENDIF
				WRITELN "};" TO gui
				WRITELN "static String uid_file_list[] = {" TO gui
				IF AMOUNT(uid$) THEN
					WRITELN "\"", HEAD$(uid$, 1), "\"" TO gui
					IF AMOUNT(uid$) > 1 THEN
						FOR item$ IN LAST$(uid$, 1)
							WRITELN ", \"", item$, "\" " TO gui
						NEXT
					ENDIF
				ELSE
					WRITELN " NULL " TO gui
				ENDIF
				WRITELN "};" TO gui
				WRITELN "MrmInitialize();" TO gui
				WRITELN "MrmOpenHierarchyPerDisplay(dpy, XtNumber(uid_file_list), uid_file_list, NULL, &hierarchy);" TO gui
				WRITELN "MrmRegisterNames(callback_list, XtNumber(callback_list));" TO gui
				WRITELN "MrmFetchWidget(hierarchy, \"main\", ", name$, ", &main_object, &class_code);" TO gui
				WRITELN "MrmCloseHierarchy(hierarchy);" TO gui
				WRITELN "XtManageChild(main_object);" TO gui
				WRITELN "#endif" TO gui
				WRITELN "free(argv[0]);" TO gui
			ELSE
				IF LEFT$(type$, 5) = "shell" OR LEFT$(type$, 10) = "simpleMenu" OR INSTR(type$, "Shell") THEN
					WRITELN name$, " = XtCreatePopupShell(\"", name$, "\", ", type$, ", ", parent$, ", args, n);" TO gui
					IF INSTR(LCASE$(type$), "shell") THEN
						WRITELN "XtVaGetValues(", name$, ", XtNwidth, &w, XtNheight, &h, NULL);" TO gui
						WRITELN "XtVaSetValues(", name$, ", XtNx, WidthOfScreen(scr)/2-(w/2), XtNy, HeightOfScreen(scr)/2-(h/2), NULL);" TO gui
					ENDIF
				ELSE
					WRITELN name$, " = XtCreateManagedWidget(\"", name$, "\", ", type$, ", ", parent$, ", args, n);" TO gui
				ENDIF
				IF LEN(callback$) THEN
					FOR item$ IN callback$
						IF HASDELIM(item$, ",") THEN
							WRITELN "XtAddCallback(", name$, ", ", TOKEN$(item$, 1, ","), ", __b2c_xt_callback, \"", TOKEN$(item$, 2, ","), "\");" TO gui
						ELSE
							WRITELN "XtAddCallback(", name$, ", ", item$, ", __b2c_xt_callback, NULL);" TO gui
						ENDIF
					NEXT
				ENDIF
			ENDIF
			WRITELN "n = 0;" TO gui
		ENDIF
	WEND

	IF g_WHICH_GUI = 2 THEN
		WRITELN "refreshCDKScreen(__main_window); setCDKFocusFirst(__main_window); resetCDKScreen(__main_window); return((uintptr_t)__main_window); }" TO gui
	ELIF g_WHICH_GUI = 1 OR g_WHICH_GUI = 3 THEN
		WRITELN "return((uintptr_t)widget_list); }" TO gui
	ELSE
		WRITELN "return((uintptr_t)__main_window); }" TO gui
	ENDIF
	CLOSE FILE gui

ENDSUB

'----------------------------------------------------------------------------------------------
' Simple parser to tokenize line.
'
' Logic: each line of source code should begin with a statement. If not, then it is considered
'   to be an assignment (LET).
' The rest of the line may contain functions, these are converted using C macros.
'----------------------------------------------------------------------------------------------

SUB Parse_Line(STRING statement$)

	LOCAL inc$, copy_curfile$, total$, txt$, sym$, exp$, then$, lft$, str$, newfeed$, token$, rel$
	LOCAL dim, i, found, copy_counter, to_parse, size, trc_backup
	LOCAL newfile, src_tmp, src_in, src_out TYPE FILE*

	SPLIT statement$ BY " " TO element$ SIZE dim

	IF dim > 0 THEN

		' See if we need to pass C code
		IF ISTRUE(g_USE_C) THEN
			IF LEFT$(statement$, 8) = "END USEC" OR element$[1] = "ENDUSEC" THEN
				g_USE_C = 0
			ELIF LEFT$(statement$, 8) = "END ENUM" OR element$[1] = "ENDENUM" THEN
				g_USE_C = 0
				WRITELN "};" TO g_CFILE
			ELSE
				WRITELN statement$ TO g_CFILE
			END IF

		ELIF ISTRUE(g_USE_H) THEN
			IF REGEX(statement$, "END.*USEH") THEN
				g_USE_H = 0
			ELIF REGEX(statement$, "END.*ENUM") OR REGEX(statement$, "END.*CLASS") THEN
				g_USE_H = 0
				WRITELN "};" TO g_HFILE
			ELSE
				WRITELN statement$ TO g_HFILE
			END IF

		ELIF LEFT$(element$[1], 2) = "#!" THEN
			'Do nothing

		ELIF LEFT$(element$[1], 1) = "'" THEN
			'Do nothing

		ELIF RIGHT$(element$[dim], 2) = "*/" THEN
			g_COMMENT = FALSE

		ELIF LEFT$(element$[1], 2) = "/*" THEN
			g_COMMENT = TRUE

		ELIF g_COMMENT = FALSE THEN

			SELECT element$[1]
				CASE "USEC"
					g_USE_C = 1

				CASE "USEH"
					g_USE_H = 1

				CASE "CLASS"
					g_USE_H = 1
					WRITELN "class ", LAST$(statement$, 1), "{" TO g_HFILE

				CASE "PRINT"
					Handle_Print(statement$, "stdout")

				CASE "EPRINT"
					Handle_Print(MID$(statement$, 2), "stderr")

				CASE "INPUT"
					Handle_Input(statement$)

				CASE "FOR"
					INCR g_LOOPCTR
					Handle_For(statement$)

				CASE "NEXT"
					WRITELN "}" TO g_CFILE
					IF g_LOOPCTR > 0 AND g_OPTION_BREAK THEN
						DECR g_LOOPCTR
						IF g_LOOPCTR > 0 THEN
							WRITELN "if(__b2c__break_ctr) {__b2c__break_ctr--; if (!__b2c__break_ctr){if(__b2c__break_flag == 1) break; else continue;} else break; }" TO g_CFILE
						END IF
					END IF

				CASE "IF"
					' Check if THEN is available
					IF NOT(ISTOKEN(statement$, "THEN")) THEN
						EPRINT NL$, "Syntax error: missing THEN in IF statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate function to C function
						then$ = CHOP$(LAST$(statement$, ISTOKEN(statement$, "THEN")))
						sym$ = HEAD$(statement$, ISTOKEN(statement$, "THEN")-1)
						exp$ = CHOP$(LAST$(sym$, ISTOKEN(sym$, "IF")))
						WRITELN "if(", Parse_Equation$(exp$), "){" TO g_CFILE
						IF LEN(then$) > 0 THEN
							trc_backup = g_TRACE
							g_TRACE = 0
							CALL Tokenize(then$)
							g_TRACE = trc_backup
							WRITELN "}" TO g_CFILE
						END IF
					ENDIF

				CASE "ELIF"
					' Check if THEN is available
					IF NOT(ISTOKEN(statement$, "THEN")) THEN
						EPRINT NL$, "Syntax error: missing THEN in ELIF statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate function to C function
						then$ = CHOP$(LAST$(statement$, ISTOKEN(statement$, "THEN")))
						sym$ = HEAD$(statement$, ISTOKEN(statement$, "THEN")-1)
						exp$ = CHOP$(LAST$(sym$, ISTOKEN(sym$, "ELIF")))
						IF LEN(then$) > 0 THEN
							IF g_TRACE = 1 THEN
								g_TRACE_PREFIX$ = "RUNTIMEDEBUG(" & g_CURFILE$ & ", " & STR$(g_COUNTER) & ", \"" & REPLACE$(statement$, CHR$(34) & CHR$(92), CHR$(39) & CHR$(47), 2) & "\")"
								WRITELN "else if(!(", g_TRACE_PREFIX$, ")){ ; }" TO g_CFILE
							ENDIF
							WRITELN "else if(", Parse_Equation$(exp$), "){" TO g_CFILE
							CALL Tokenize(then$)
							WRITELN "}" TO g_CFILE
						ELSE
							IF g_TRACE = 1 THEN
								g_TRACE_PREFIX$ = "RUNTIMEDEBUG(" & g_CURFILE$ & ", " & STR$(g_COUNTER) & ", \"ELIF " & REPLACE$(exp$, CHR$(34) & CHR$(92), CHR$(39) & CHR$(47), 2) & "\")"
								WRITELN "} else if(!(", g_TRACE_PREFIX$, ")){ ;" TO g_CFILE
							ENDIF
							WRITELN "} else if(", Parse_Equation$(exp$), "){" TO g_CFILE
							IF g_TRACE = 1 THEN g_TRACE_PREFIX$ = ""
						END IF
					END IF

				CASE "ELSE"
					' Translate function to C function
					exp$ = CHOP$(LAST$(statement$, ISTOKEN(statement$, "ELSE")))
					IF LEN(exp$) > 0 THEN
						IF g_TRACE = 1 THEN
							g_TRACE_PREFIX$ = "RUNTIMEDEBUG(" & g_CURFILE$ & ", " & STR$(g_COUNTER) & ", \"" & REPLACE$(statement$, CHR$(34) & CHR$(92), CHR$(39) & CHR$(47), 2) & "\")"
							WRITELN "else if(!(", g_TRACE_PREFIX$, ")){ ; }" TO g_CFILE
						ENDIF
						WRITELN "else {" TO g_CFILE
						CALL Tokenize(exp$)
						WRITELN "}" TO g_CFILE
					ELSE
						IF g_TRACE = 1 THEN
							g_TRACE_PREFIX$ = "RUNTIMEDEBUG(" & g_CURFILE$ & ", " & STR$(g_COUNTER) & ", \"ELSE\")"
							WRITELN "} else if(!(", g_TRACE_PREFIX$, ")){ ;" TO g_CFILE
						ENDIF
						WRITELN "} else {" TO g_CFILE
						IF g_TRACE = 1 THEN g_TRACE_PREFIX$ = ""
					END IF

				CASE "FI"
					WRITELN "}" TO g_CFILE

				CASE "DOTIMES"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty DOTIMES at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						Register_Numeric("_", FALSE)
						WRITELN "long __do_times_", g_DOTIMES, ";" TO g_HFILE
						WRITELN "for(__do_times_", g_DOTIMES, " = 0; __do_times_", g_DOTIMES, "<", MID$(statement$, INSTR(statement$, "DOTIMES") + 7), "; __do_times_", g_DOTIMES, "++) { _ = __do_times_", g_DOTIMES, "+1;" TO g_CFILE
						INCR g_DOTIMES
					END IF

				CASE "DO"
					WRITELN "{" TO g_CFILE

				CASE "DONE"
					WRITELN "}" TO g_CFILE

				CASE "WHILE"
					INCR g_LOOPCTR
					Handle_While(statement$)

				CASE "WEND"
					WRITELN "}" TO g_CFILE
					IF g_LOOPCTR > 0 AND g_OPTION_BREAK THEN
						DECR g_LOOPCTR
						IF g_LOOPCTR > 0 THEN
							WRITELN "if(__b2c__break_ctr) {__b2c__break_ctr--; if (!__b2c__break_ctr){if(__b2c__break_flag == 1) break; else continue;} else break; }" TO g_CFILE
						END IF
					END IF

				CASE "BREAK"
					' Check argument
					IF g_OPTION_BREAK THEN
						IF dim > 1 AND VAL(MID$(statement$, INSTR(statement$, "BREAK") + 5)) <> 0 THEN
							WRITELN "__b2c__break_ctr = ", MID$(statement$, INSTR(statement$, "BREAK") + 5), "-1; __b2c__break_flag = 1;" TO g_CFILE
						END IF
						WRITELN "break;" TO g_CFILE
					ELSE
						EPRINT NL$, "Syntax error: use of BREAK at line ", g_COUNTER, " in file '", g_CURFILE$, "' was disbaled!"
						END 1
					ENDIF

				CASE "CONTINUE"
					' Check argument
					IF dim > 1 AND VAL(MID$(statement$, INSTR(statement$, "CONTINUE") + 8)) <> 0 THEN
						WRITELN "__b2c__break_ctr = ", MID$(statement$, INSTR(statement$, "CONTINUE") + 8), "-1; __b2c__break_flag = 2;" TO g_CFILE
					END IF
					IF VAL(MID$(statement$, INSTR(statement$, "CONTINUE") + 8)) > 1 THEN
						WRITELN "break;" TO g_CFILE
					ELSE
						WRITELN "continue;" TO g_CFILE
					END IF

				CASE "REPEAT"
					INCR g_LOOPCTR
					WRITELN "do{" TO g_CFILE

				CASE  "UNTIL"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty UNTIL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Convert to legal C code
						exp$ = Parse_Equation$(MID$(statement$, INSTR(statement$, "UNTIL") + 5) )
						WRITELN "} while(!(", exp$, "));" TO g_CFILE
						IF g_LOOPCTR > 0 AND g_OPTION_BREAK THEN
							DECR g_LOOPCTR
							IF g_LOOPCTR > 0 THEN
								WRITELN "if(__b2c__break_ctr) {__b2c__break_ctr--; if (!__b2c__break_ctr){if(__b2c__break_flag == 1) break; else continue;} else break; }" TO g_CFILE
							END IF
						END IF
					END IF

				CASE "LET"
					Handle_Let(MID$(statement$, INSTR(statement$, "LET") + 3))

				CASE "SYSTEM"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty SYSTEM at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						WRITELN "SYSTEM (", MID$(statement$, INSTR(statement$, "SYSTEM") + 6), ");" TO g_CFILE
					END IF

				CASE "SLEEP"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty SLEEP at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						WRITELN "usleep(", MID$(statement$, INSTR(statement$, "SLEEP") + 5), "*1000);" TO g_CFILE
					END IF

				CASE "OPEN"
					Handle_Open(statement$)

				CASE "CLOSE"
					' Check argument
					IF dim < 3 THEN
						EPRINT NL$, "Syntax error: empty CLOSE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						exp$ = LAST$(statement$, 1)
						SELECT element$[2]
							CASE "FILE"
								exp$ = LAST$(exp$, 1)
								WHILE LEN(exp$)
									token$ = Mini_Parser$(exp$)
									WRITELN "fclose(", token$, ");" TO g_CFILE
									exp$ = MID$(exp$, LEN(token$)+2)
									token$ = CHOP$(token$)
									FREE g_SEMANTIC_OPENCLOSE$(token$)
								WEND
							CASE "DIRECTORY"
								exp$ = LAST$(exp$, 1)
								WHILE LEN(exp$)
									token$ = Mini_Parser$(exp$)
									WRITELN "closedir(", token$, ");" TO g_CFILE
									exp$ = MID$(exp$, LEN(token$)+2)
									token$ = CHOP$(token$)
									FREE g_SEMANTIC_OPENCLOSE$(token$)
								WEND
							CASE "MEMORY"
								exp$ = LAST$(exp$, 1)
								WHILE LEN(exp$)
									token$ = Mini_Parser$(exp$)
									WRITELN token$, " = NULL;" TO g_CFILE
									exp$ = MID$(exp$, LEN(token$)+2)
									token$ = CHOP$(token$)
									FREE g_SEMANTIC_OPENCLOSE$(token$)
								WEND
							CASE "LIBRARY"
								exp$ = LAST$(exp$, 1)
								WHILE LEN(exp$)
									token$ = Mini_Parser$(exp$)
									WRITELN "if(__b2c__dlopen__pointer_", EXTRACT$(token$, "[[:punct:]]", TRUE), " != NULL) {dlclose(__b2c__dlopen__pointer_", EXTRACT$(token$, "[[:punct:]]", TRUE), "); __b2c__dlopen__pointer_", EXTRACT$(token$, "[[:punct:]]", TRUE), " = NULL;}" TO g_CFILE
									exp$ = MID$(exp$, LEN(token$)+2)
									token$ = CHOP$(token$)
								WEND
							CASE "NETWORK";
							CASE "SERVER";
							CASE "UDP";
							CASE "DEVICE"
								exp$ = LAST$(exp$, 1)
								WHILE LEN(exp$)
									token$ = Mini_Parser$(exp$)
									' Close SSL socket if option was set
									IF g_OPTION_TLS THEN
										WRITELN "SSL_shutdown((SSL*)", token$, ");" TO g_CFILE
										WRITELN "SSL_free((SSL*)", token$, ");" TO g_CFILE
									ELSE
										WRITELN "shutdown((uintptr_t)", token$, ", SHUT_RDWR);" TO g_CFILE
										WRITELN "close((uintptr_t)", token$, ");" TO g_CFILE
									ENDIF
									exp$ = MID$(exp$, LEN(token$)+2)
									token$ = CHOP$(token$)
									FREE g_SEMANTIC_OPENCLOSE$(token$)
								WEND
							DEFAULT
								EPRINT NL$, "Syntax error: erroneous CLOSE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
						END SELECT
					END IF

				CASE "REWIND"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty REWIND at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						WRITELN "rewind(", element$[2], ");" TO g_CFILE
					END IF

				CASE "MEMREWIND"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty MEMREWIND at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						WRITELN element$[2], " = (char*)__b2c_mem_", element$[2], ";" TO g_CFILE
					END IF

				CASE "SEEK"
					Handle_Seek(statement$)

				CASE "READLN"
					Handle_Readln(statement$)

				CASE "WRITELN"
					Handle_Writeln(statement$)

				CASE "GETBYTE"
					Handle_Getbyte(statement$)

				CASE "PUTBYTE"
					Handle_Putbyte(statement$)

				CASE "GETFILE"
					Handle_Getfile(statement$)

				CASE "GETLINE"
					Handle_Getline(statement$)

				CASE "PUTLINE"
					Handle_Putline(statement$)

				CASE "END";
				CASE "ENDIF";
				CASE "ENDSUB";
				CASE "ENDFUNC";
				CASE "ENDWITH";
				CASE "ENDFORK";
				CASE "ENDRECORD";
				CASE "ENDSELECT";
				CASE "ENDFUNCTION"
					exp$ = IIF$(dim > 1, element$[2], MID$(element$[1], 4))
					SELECT exp$
						CASE "IF"
							WRITELN "}" TO g_CFILE
						CASE "RECORD"
							IF LEN(g_FUNCNAME$) > 0 THEN
								WRITELN "}", g_RECORDNAME$, ";" TO g_CFILE
								WRITELN "typedef ", g_RECORDNAME$, " ", EXTRACT$(g_RECORDNAME$, "_TYPE"), "_type;" TO g_CFILE
								IF LEN(g_RECORDARRAY$) THEN
									WRITELN g_RECORDNAME$, " *", LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1), " = (", g_RECORDNAME$, "*)calloc(", g_RECORDARRAY$, "+", g_OPTION_BASE, ", sizeof(", g_RECORDNAME$, "));" TO g_CFILE
									g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1)
									g_RECORDEND_BODY$ = " long __b2c_record_" & EXTRACT$(g_RECORDNAME$, "_TYPE") & " = " & g_RECORDARRAY$ & "+" & STR$(g_OPTION_BASE) & ";" & g_RECORDEND_BODY$
								ELSE
									WRITELN g_RECORDNAME$, " ", REPLACE$(g_RECORDVAR$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { 0 } ;" TO g_CFILE
								ENDIF
							ELSE
								WRITELN "}", g_RECORDNAME$, ";" TO g_HFILE
								WRITELN "typedef ", g_RECORDNAME$, " ", EXTRACT$(g_RECORDNAME$, "_TYPE") , "_type;" TO g_HFILE
								IF LEN(g_RECORDARRAY$) THEN
									WRITELN g_RECORDNAME$, " *", LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1), ";" TO g_HFILE
									WRITELN LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1), " = (", g_RECORDNAME$, "*)calloc(", g_RECORDARRAY$, "+", g_OPTION_BASE, ", sizeof(", g_RECORDNAME$, "));" TO g_CFILE
									WRITELN "long __b2c_record_" & EXTRACT$(g_RECORDNAME$, "_TYPE") & ";" TO g_HFILE
									g_RECORDEND_BODY$ = g_RECORDEND_BODY$ & " __b2c_record_" & EXTRACT$(g_RECORDNAME$, "_TYPE") & " = " & g_RECORDARRAY$ & "+" & STR$(g_OPTION_BASE) & ";"
								ELSE
									WRITELN g_RECORDNAME$, " ", REPLACE$(g_RECORDVAR$, "]", "+" & STR$(g_OPTION_BASE) & "]"), " = { 0 } ;" TO g_HFILE
								ENDIF
								WRITELN g_RECORDEND_HEADER$ TO g_HFILE
							END IF
							WRITELN g_RECORDEND_BODY$ TO g_CFILE
							g_RECORDNAME$ = ""
							g_RECORDVAR$ = ""
							g_RECORDEND_BODY$ = ""
							g_RECORDEND_HEADER$ = ""
							g_RECORDARRAY$ = ""
							' Restore function name if GLOBAL was used
							IF LEN(g_RECORDCACHE$) > 0 THEN
								g_FUNCNAME$ = g_RECORDCACHE$
								g_RECORDCACHE$ = ""
							ENDIF
						CASE "FUNC", "FUNCTION"
							Handle_Endfunction
						CASE "SUB"
							Handle_Endsub
						CASE "WITH"
							g_WITHVAR$ = ""
						CASE "SELECT"
							IF g_SELECTVAR_CTR = 0 THEN
								EPRINT NL$, "Syntax error: invalid END SELECT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							ELSE
								WRITELN "}" TO g_CFILE
								g_SELECTVAR$[g_SELECTVAR_CTR] = ""
								g_IN_CASE[g_SELECTVAR_CTR] = 0
								g_CASE_FALL$ = ""
								g_CASE_CONT$ = ""
								DECR g_SELECTVAR_CTR
							END IF
						CASE "FORK"
							IF dim > 2 THEN
								WRITELN "_exit(", MID$(statement$, INSTR(statement$, "FORK")+4), ");" TO g_CFILE
							ELSE
								WRITELN "_exit(EXIT_SUCCESS);" TO g_CFILE
							ENDIF
						DEFAULT
							WRITELN "exit(", IIF$(dim > 1, MID$(statement$, INSTR(statement$, "END")+3), "EXIT_SUCCESS"), ");" TO g_CFILE
					END SELECT

				CASE "SUB"
					Handle_SubFunc(statement$)

				CASE "CALL"
					Handle_Call(statement$)

				CASE "FUNCTION"
					Handle_SubFunc(statement$)

				CASE "FUNC"
					Handle_SubFunc(statement$)

				CASE "RETURN"
					Handle_Return(MID$(statement$, INSTR(statement$, "RETURN") + 6))

				CASE "IMPORT"
					Handle_Import(statement$)

				CASE "DECLARE"
					Handle_Declare(MID$(statement$, INSTR(statement$, "DECLARE") + 7))

				CASE "GLOBAL"
					Handle_Declare(MID$(statement$, INSTR(statement$, "GLOBAL") + 6))

				CASE "LOCAL"
					Handle_Local(MID$(statement$, INSTR(statement$, "LOCAL") + 5))

				CASE "DATA"
					Handle_Data(statement$)

				CASE "RESTORE"
					IF dim = 1 THEN
						WRITELN "__b2c__floatarray_ptr = 0;" TO g_CFILE
						WRITELN "__b2c__stringarray_ptr = 0;" TO g_CFILE
					ELSE
						WRITELN "__b2c__floatarray_ptr = __b2c__label_floatarray_", element$[2], ";" TO g_CFILE
						WRITELN "__b2c__stringarray_ptr = __b2c__label_stringarray_", element$[2], ";" TO g_CFILE
					END IF

				CASE "READ"
					Handle_Read(statement$)

				CASE "PUSH"
					Handle_Push(statement$)

				CASE "PULL"
					Handle_Pull(statement$)

				CASE "SEED"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty DATA at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						WRITELN "srandom((unsigned int)", MID$(statement$, INSTR(statement$, " ")+1), ");" TO g_CFILE
					END IF

				CASE "DEF"
					Handle_Deffn(statement$)

				CASE "CONST"
					Handle_Const(statement$)

				CASE "INCLUDE"
					' Get rid of doublequotes if they are there
					inc$ = EXTRACT$((CHOP$(MID$(statement$, INSTR(statement$, " ") + 1))), CHR$(34))
					' See if there are arguments
					IF INSTR(inc$, ",") THEN
						SPLIT MID$(inc$, INSTR(inc$, ",")+1) BY "," TO element$ SIZE size
						FOR i = 1 TO size
							element$[i] = EXTRACT$(element$[i], g_STRINGSIGN$)
						NEXT
						inc$ = MID$(inc$, 1, INSTR(inc$, ",")-1)
					ELSE
						to_parse = 2
					END IF
					' Check file extension
					IF RIGHT$(inc$, 4) <> ".bac" THEN inc$ = inc$ & ".bac"

					' Check argument
					IF NOT(FILEEXISTS(inc$)) OR dim = 1 OR (FILETYPE(inc$) != 1 AND FILETYPE(inc$) != 6) THEN
						EPRINT NL$, "System error: missing file '", inc$, "' for INCLUDE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Clear current terminal line
						PRINT CR$, EL$;
						' Check if the C Preprocessor needs to run
						IF ISTRUE(g_CPP) THEN
							IF ISTRUE(LEN(EXEC$("which cpp 2>/dev/null"))) THEN
								PRINT "Preprocessing '", inc$, "'... ";
								' Change next line marker to overcome C preprocessor interpretation
								OPEN inc$ & ".tmp" FOR WRITING AS src_tmp
								OPEN inc$ FOR READING AS src_in
								WHILE NOT(ENDFILE(src_in))
									READLN txt$ FROM src_in
									IF LEFT$(txt$, 1) = "#" THEN
										WRITELN txt$ TO src_tmp
									ELSE
										WRITELN "@" & txt$ & "@" TO src_tmp
									ENDIF
								WEND
								CLOSE FILE src_in, src_tmp
								SYSTEM "cpp -P -w " & inc$ & ".tmp " & inc$ & ".cpp"
								' Restore next line marker
								OPEN inc$ & ".cpp" FOR READING AS src_cpp
								OPEN inc$ & ".bac2" FOR WRITING AS src_out
								WHILE NOT(ENDFILE(src_cpp))
									READLN txt$ FROM src_cpp
									WRITELN MID$(txt$, 2, LEN(txt$)-2) TO src_out
								WEND
								CLOSE FILE src_out, src_cpp
								newfeed$ = inc$ & ".bac2"
								g_TMP_FILES$ = g_TMP_FILES$ & " " & inc$ & ".cpp" & " " & inc$ & ".tmp" & " " & inc$ & ".bac2"
								PRINT "done."
							ELSE
								EPRINT "System error: the C Preprocessor 'cpp' not found on this system! Exiting..."
								END 1
							END IF
						ELSE
							newfeed$ = inc$
						END IF
						g_TMP_FILES$ = g_TMP_FILES$ & " " & inc$
						' Start walking through program
						copy_counter = g_COUNTER
						g_COUNTER = 1
						' Assign new file
						copy_curfile$ = g_CURFILE$
						' Set current filename
						g_CURFILE$ = newfeed$

						OPEN newfeed$ FOR READING AS newfile
						REPEAT
							READLN txt$ FROM newfile
							' See if we need to enable flag
							IF size > 0 THEN
								FOR i = 1 TO size
									IF ( to_parse = 0 AND REGEX(CHOP$(MID$(txt$, INSTR(txt$, " "))), "^" & CHOP$(element$[i])) AND REGEX(txt$, "SUB|FUNCTION") ) OR REGEX(txt$, "INCLUDE$") THEN
										to_parse = 1
										BREAK
									END IF
								NEXT
							END IF
							' Line is not empty?
							IF LEN(txt$) > 0 AND to_parse > 0 THEN
								IF NOT(g_QUIET) THEN PRINT "\rConverting '", newfeed$, "'... ", g_COUNTER, EL$;
								IF RIGHT$(txt$, 1) = CR$ THEN
									EPRINT "\nSystem error: Windows file detected! Remove non-Unix CR line separators first. Exiting..."
									END 1
								ELIF RIGHT$(txt$, 2) = " \\" AND LEFT$(txt$, 1) != CHR$(39) THEN
									total$ = total$ & LEFT$(txt$, LEN(txt$)-2)
								ELSE
									total$ = CHOP$(total$ & txt$)
									IF LEFT$(total$, 1) != CHR$(39) THEN
										IF g_DEBUG THEN
											WRITELN "/* line ", g_COUNTER, " \"", newfeed$, "\" */" TO g_CFILE
											WRITELN "/* line ", g_COUNTER, " \"", newfeed$, "\" */" TO g_HFILE
										ELSE
											WRITELN "#line ", g_COUNTER, " \"", newfeed$, "\"" TO g_CFILE
											WRITELN "#line ", g_COUNTER, " \"", newfeed$, "\"" TO g_HFILE
										ENDIF
										CALL Tokenize(total$)
									END IF
									LET total$ = ""
								END IF
							ENDIF
							' See if we need to stop parsing
							IF to_parse = 1 AND INSTR(txt$, "END") AND REGEX(txt$, "SUB|FUNCTION") THEN to_parse = 0
							' Increase line number
							INCR g_COUNTER
						UNTIL ENDFILE(newfile)
						CLOSE FILE newfile

						' Save total amount of lines
						INCR g_TOTAL_LINES, g_COUNTER
						' Restore original counter
						g_COUNTER = copy_counter
						' Restore original file
						g_CURFILE$ = copy_curfile$
						' Set DATA array indexes correctly
						WRITELN "__b2c__stringarray_ptr = ", g_CCTR, ";" TO g_CFILE
						WRITELN "__b2c__floatarray_ptr = ", g_FCTR, ";" TO g_CFILE
					END IF

				CASE "POKE"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty POKE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						exp$ = MID$(statement$, INSTR(statement$, "POKE") + 4)
						IF TALLY(exp$, " SIZE ") THEN
							str$ = TOKEN$(exp$, 2, " SIZE ")
							exp$ = TOKEN$(exp$, 1, " SIZE ")
							token$ = Mini_Parser$(exp$)
							exp$ = MID$(exp$, LEN(token$)+2)
							WRITELN "if (__b2c__trap){if(__b2c__memory__check((char*)", token$, ", (" & str$ & ")*sizeof(__b2c__MEMTYPE))) {ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"POKE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
							WRITELN "memset((void*)(__b2c__MEMTYPE*)(" & token$ & "), " & exp$ & ", (" & str$ & ")*sizeof(__b2c__MEMTYPE));" TO g_CFILE
						ELSE
							token$ = Mini_Parser$(exp$)
							exp$ = MID$(exp$, LEN(token$)+2)
							WRITELN "if (__b2c__trap){if(__b2c__memory__check((char*)", token$, ", sizeof(__b2c__MEMTYPE))) {ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"POKE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
							WRITELN "*(__b2c__MEMTYPE*)(", token$, ") = ( __b2c__MEMTYPE)(", exp$, ");" TO g_CFILE
						ENDIF
						IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
					END IF

				CASE "RESIZE"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty RESIZE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						exp$ = MID$(statement$, INSTR(statement$, "RESIZE") + 6)
						lft$ = CHOP$(TOKEN$(exp$, 1, " TO "))
						str$ = CHOP$(TOKEN$(exp$, 2, " TO "))
						WRITELN "if(__b2c__trap) {if(__b2c__memory__check((char*)", lft$, ", sizeof(__b2c__MEMTYPE))) {ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"RESIZE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
						WRITELN lft$, " = (", Get_Var$(EXTRACT$(lft$, "."), g_FUNCNAME$), ")realloc((void*)", lft$, ", sizeof(__b2c__MEMTYPE)*(", str$, "+1));" TO g_CFILE
						WRITELN "if(__b2c__trap) {if((void*)", lft$, " == NULL) {ERROR=6; if(!__b2c__catch_set) RUNTIMEERROR(\"RESIZE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
						IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
					END IF

				CASE "COPY"
					Handle_Copy(statement$)

				CASE "DELETE"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty DELETE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate to C function
						IF element$[2] = "FILE" THEN
							WRITELN "if (unlink(", MID$(statement$, INSTR(statement$, " FILE ") + 6), ")==-1){if(__b2c__trap){ERROR = 7;if(!__b2c__catch_set) RUNTIMEERROR(\"DELETE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
							IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
						ELIF element$[2] = "DIRECTORY" THEN
							WRITELN "if (rmdir(", MID$(statement$, INSTR(statement$, " DIRECTORY ") + 11), ") == -1){if(__b2c__trap){ERROR = 20;if(!__b2c__catch_set) RUNTIMEERROR(\"DELETE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
							IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
						ELIF element$[2] = "RECURSIVE" THEN
							WRITELN "__b2c__rmrecursive(__LINE__, __FILE__, ", MID$(statement$, INSTR(statement$, " RECURSIVE ") + 11), ");" TO g_CFILE
						ELIF ISTOKEN(statement$, "FROM") THEN
							sym$ = CHOP$(LAST$(statement$, ISTOKEN(statement$, "FROM")))
							exp$ = HEAD$(statement$, ISTOKEN(statement$, "FROM")-1)
							exp$ = LAST$(exp$, ISTOKEN(exp$, "DELETE"))
							IF Get_Var$("__b2c__tree_" & sym$, g_FUNCNAME$) = "__b2c__sortstr" THEN
								WRITELN "__b2c__assign = *(char**)", exp$, "; tdelete((void*)", exp$, ", &", sym$, ", ", Get_Var$("__b2c__tree_" & sym$, g_FUNCNAME$), "); free(__b2c__assign);" TO g_CFILE
							ELSE
								WRITELN "tdelete((void*)", exp$, ", &", sym$, ", ", Get_Var$("__b2c__tree_" & sym$, g_FUNCNAME$), ");" TO g_CFILE
							ENDIF
						ELSE
							EPRINT NL$, "Syntax error: erronuous argument for DELETE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
							END 1
						END IF
					END IF

				CASE "RENAME"
					Handle_Rename(statement$)

				CASE "MAKEDIR"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty MAKEDIR at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate to C function
						WRITELN "ERROR = __b2c__makedir(", LAST$(statement$, 1), "); if(ERROR && __b2c__trap){ if(!__b2c__catch_set) RUNTIMEERROR(\"MAKEDIR\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";}" TO g_CFILE
						IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
					END IF

				CASE "CHANGEDIR"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty CHANGEDIR at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate to C function
						WRITELN "if(chdir(", LAST$(statement$, 1), ") == -1){if(__b2c__trap) {ERROR = 22;if(!__b2c__catch_set) RUNTIMEERROR(\"CHANGEDIR\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
						IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
					END IF

				CASE "FREE"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty FREE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate to C function
						IF REGEX(statement$, "[a-zA-Z]+\\(.*\\)$") THEN
							' Start miniparser
							exp$ = LAST$(statement$, 1)
							WHILE LEN(exp$)
								token$ = CHOP$(LEFT$(exp$, INSTR(exp$, "(")-1))
								str$ = CHOP$(Mini_Parser$(exp$))
								txt$ = MID$(str$, INSTR(str$, "(")+1)
								WRITELN "__b2c__hash_del(__b2c__assoc_", token$, ", ", LEFT$(txt$, LEN(txt$)-1), ");" TO g_CFILE
								exp$ = MID$(exp$, LEN(str$)+2)
							WEND
						ELSE
							FOR str$ IN EXTRACT$(LAST$(statement$, 1), " ") STEP ","
								IF LEN(Get_Var$("__b2c__assoc_" & str$)) OR LEN(Get_Var$("__b2c__assoc_" & str$, g_FUNCNAME$)) THEN
									WRITELN "__b2c__hash_clear(__b2c__assoc_", str$, ");" TO g_CFILE
								ELSE
									WRITELN "if(__b2c__trap){if(__b2c__memory__check((char *)", str$, ", sizeof(__b2c__MEMTYPE)))" TO g_CFILE
									WRITELN "{ERROR=1; if(!__b2c__catch_set) RUNTIMEERROR(\"FREE\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} } free((void*)", str$, ");" TO g_CFILE
									FREE g_SEMANTIC_MEMFREE$(str$)
								ENDIF
							NEXT
							IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
						END IF
					END IF

				CASE "ON"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty ON at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELIF NOT(ISTOKEN(statement$, "GOTO")) AND NOT(INSTR(statement$, "CALL")) THEN
						EPRINT NL$, "Syntax error: ON without CALL/GOTO at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						PARSE COLLAPSE$(statement$) WITH "ON * " & IIF$(ISTOKEN(statement$, "CALL"), "CALL", "GOTO") & " *" TO match$
						' Convert to C 'switch' statement
						i = 1
						WRITELN "switch(", match$[1], "){" TO g_CFILE
						WHILE LEN(match$[2])
							token$ = Mini_Parser$(match$[2])
							IF ISTOKEN(statement$, "GOTO") THEN
								WRITELN "case ", i, ": goto ", token$, "; break;" TO g_CFILE
							ELSE
								IF NOT(REGEX(token$, "\\(.*\\)$")) THEN
									WRITELN "case ", i, ": ", token$, "(); break;" TO g_CFILE
								ELSE
									WRITELN "case ", i, ": ", token$, "; break;" TO g_CFILE
								ENDIF
							ENDIF
							match$[2] = MID$(match$[2], LEN(token$)+2)
							INCR i
						WEND
						WRITELN "}" TO g_CFILE
					END IF

				CASE "GOTO"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty GOTO at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate to C label
						WRITELN "goto ", element$[2], ";" TO g_CFILE
					END IF

				CASE "GOSUB"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty GOSUB at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate to C label
						WRITELN "__b2c__gosub_buffer_ptr++; if (__b2c__gosub_buffer_ptr >= ", g_MAX_RBUFFERS, ") {ERROR=31; if(!__b2c__catch_set) RUNTIMEERROR(\"GOSUB\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";}" TO g_CFILE
						WRITELN "if(!setjmp(__b2c__gosub_buffer[__b2c__gosub_buffer_ptr])) goto ", element$[2], ";" TO g_CFILE
						WRITELN "__b2c__gosub_buffer_ptr--; if(__b2c__gosub_buffer_ptr < -1) __b2c__gosub_buffer_ptr = -1;" TO g_CFILE
						IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
					END IF

				CASE "LABEL"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty LABEL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Translate to C label
						WRITELN element$[2], ":" TO g_CFILE
						WRITELN ";" TO g_CFILE
						' Needed for RESTORE
						IF NOT(LEN(Get_Var$("__b2c__label_floatarray_" & element$[2]))) THEN
							WRITELN "int __b2c__label_floatarray_", element$[2], ";" TO g_HFILE
							WRITELN "int __b2c__label_stringarray_", element$[2], ";" TO g_HFILE
							Save_Main_Var("__b2c__label_floatarray_" & element$[2], "int")
							Save_Main_Var("__b2c__label_stringarray_" & element$[2], "int")
						ENDIF
						WRITELN "__b2c__label_floatarray_", element$[2], " = ", g_FCTR, ";" TO g_CFILE
						WRITELN "__b2c__label_stringarray_", element$[2], " = ", g_CCTR, ";" TO g_CFILE
					END IF

				CASE "TRAP"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty TRAP at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						IF element$[2] = "LOCAL" THEN
							WRITELN "/* Error catching is enabled */" TO g_CFILE
							WRITELN "__b2c__trap = 1;" TO g_CFILE
							WRITELN "signal(SIGILL, __b2c__catch_signal);" TO g_CFILE
							WRITELN "signal(SIGABRT, __b2c__catch_signal);" TO g_CFILE
							WRITELN "signal(SIGFPE, __b2c__catch_signal);" TO g_CFILE
							WRITELN "signal(SIGSEGV, __b2c__catch_signal);" TO g_CFILE
						ELIF element$[2] = "SYSTEM" THEN
							WRITELN "/* Error catching is disabled */" TO g_CFILE
							WRITELN "__b2c__trap = 0;" TO g_CFILE
							WRITELN "signal(SIGILL, SIG_DFL);" TO g_CFILE
							WRITELN "signal(SIGABRT, SIG_DFL);" TO g_CFILE
							WRITELN "signal(SIGFPE, SIG_DFL);" TO g_CFILE
							WRITELN "signal(SIGSEGV, SIG_DFL);" TO g_CFILE
						ELSE
							EPRINT NL$, "Syntax error: invalid argument for TRAP at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
							END 1
						END IF
					END IF

				CASE "CATCH"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty CATCH at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELIF element$[2] = "GOTO" THEN
						WRITELN "__b2c__catch_set = 1;" TO g_CFILE
						g_CATCHGOTO$ = element$[3]
					ELIF element$[2] = "ERROR" THEN
						WRITELN "__b2c__error_callback = & ", element$[3], ";" TO g_CFILE
					ELIF element$[2] = "RESET" THEN
						WRITELN "__b2c__catch_set = 0;" TO g_CFILE
						g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT"
					ELSE
						EPRINT NL$, "Syntax error: CATCH without GOTO or RESET at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					END IF

				CASE "RESUME"
					WRITELN "longjmp(__b2c__jump, 1);" TO g_CFILE

				CASE "CLEAR"
					WRITELN "fprintf(stdout,\"\\033[2J\"); fprintf(stdout,\"\\033[0;0f\");fflush(stdout);" TO g_CFILE

				CASE "COLOR"
					Handle_Color(statement$)

				CASE "TYPE"
					Handle_Type(statement$)

				CASE "SCREEN"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty SCREEN at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						IF element$[2] = "SAVE" THEN
							WRITELN "fprintf(stdout,\"\\033[?47h\"); fflush(stdout);" TO g_CFILE
						ELIF element$[2] = "RESTORE" THEN
							WRITELN "fprintf(stdout,\"\\033[?47l\"); fflush(stdout);" TO g_CFILE
						ELSE
							EPRINT NL$, "Syntax error: invalid argument for SCREEN at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
							END 1
						END IF
					END IF

				CASE "GOTOXY"
					Handle_Gotoxy(statement$)

				CASE "RECEIVE"
					Handle_Receive(CHOP$(MID$(statement$, INSTR(statement$, "RECEIVE") + 7)))

				CASE "SEND"
					Handle_Send(MID$(statement$, INSTR(statement$, "SEND") + 4))

				CASE "RECORD"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty RECORD at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELIF ISTRUE(LEN(g_RECORDNAME$)) THEN
						EPRINT NL$, "Syntax error: cannot define a record within a record!"
						END 1
					ELSE
						' Determine name
						g_RECORDVAR$ = MID$(statement$, INSTR(statement$, "RECORD")+6)
						IF INSTR(g_RECORDVAR$, " ARRAY ") THEN
							g_RECORDARRAY$ = MID$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "ARRAY")+5)
							g_RECORDVAR$ = CHOP$(LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "ARRAY")-1)) & "[" & g_RECORDARRAY$ & "]"
						ENDIF
						' Translate to C typedef struct
						IF ISTRUE(LEN(g_FUNCNAME$)) THEN
							g_RECORDNAME$ = LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1) & "_TYPE"
							WRITELN "typedef struct {" TO g_CFILE
							Save_Func_Var("", g_FUNCNAME$, g_RECORDNAME$)
						ELSE
							g_RECORDNAME$ = LEFT$(g_RECORDVAR$, INSTR(g_RECORDVAR$, "[")-1) & "_TYPE"
							WRITELN "typedef struct {" TO g_HFILE
							Save_Main_Var("", g_RECORDNAME$)
						ENDIF
					ENDIF

				CASE "WITH"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty WITH at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELIF ISTRUE(LEN(g_RECORDNAME$)) THEN
						EPRINT NL$, "Syntax error: cannot define a WITH within a WITH!"
						END 1
					ELSE
						g_WITHVAR$ = element$[2]
					END IF

				CASE "SPLIT"
					Handle_Split(statement$)

				CASE "JOIN"
					Handle_Join(statement$)

				CASE "SELECT"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty SELECT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						INCR g_SELECTVAR_CTR
						IF Check_String_Type(MID$(statement$, INSTR(statement$, "SELECT") + 6)) THEN
							g_SELECTVAR$[g_SELECTVAR_CTR] = "__b2c__select_" & STR$(g_COUNTER) & g_STRINGSIGN$
							IF LEN(g_FUNCNAME$) THEN
								g_STRINGARGS$ = g_STRINGARGS$ & " char* " & g_SELECTVAR$[g_SELECTVAR_CTR] & " = NULL;"
								g_LOCALSTRINGS$ = g_LOCALSTRINGS$ & " " & g_SELECTVAR$[g_SELECTVAR_CTR]
							ELSE
								WRITELN "char* ", g_SELECTVAR$[g_SELECTVAR_CTR], " = NULL;" TO g_HFILE
							ENDIF
							WRITELN "if(" & g_SELECTVAR$[g_SELECTVAR_CTR], ") { free(" & g_SELECTVAR$[g_SELECTVAR_CTR], "); } " & g_SELECTVAR$[g_SELECTVAR_CTR], " = __b2c__strdup((const char*)", MID$(statement$, INSTR(statement$, "SELECT") + 6), ");" TO g_CFILE
						ELSE
							g_SELECTVAR$[g_SELECTVAR_CTR] = "__b2c__select_" & STR$(g_COUNTER)
							WRITELN "double ", g_SELECTVAR$[g_SELECTVAR_CTR], ";" TO g_HFILE
							WRITELN g_SELECTVAR$[g_SELECTVAR_CTR], " = (double)", MID$(statement$, INSTR(statement$, "SELECT") + 6), ";" TO g_CFILE
						ENDIF
						g_IN_CASE[g_SELECTVAR_CTR] = 0
						g_CASE_FALL$ = ""
						g_CASE_CONT$ =""
					END IF

				CASE "CASE"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty CASE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' In processing of next CASE statements
						IF ISTRUE(g_IN_CASE[g_SELECTVAR_CTR]) THEN g_CASE_CONT$ = "} else "
						' Create IF
						IF Check_String_Type(g_SELECTVAR$[g_SELECTVAR_CTR]) THEN
							exp$ = MID$(statement$, INSTR(statement$, "CASE") + 4)
							IF RIGHT$(statement$, 1) = ";" THEN
								g_CASE_FALL$ = g_CASE_FALL$ & "!__b2c__strcmp(" & g_SELECTVAR$[g_SELECTVAR_CTR] & ", " & LEFT$(exp$, LEN(exp$)-1) & ") ||"
							ELSE
								WHILE LEN(exp$)
									str$ = Mini_Parser$(exp$)
									g_CASE_FALL$ = g_CASE_FALL$ & "!__b2c__strcmp(" & g_SELECTVAR$[g_SELECTVAR_CTR] & ", " & str$ & ") "
									exp$ = MID$(exp$, LEN(str$)+2)
									IF LEN(exp$) THEN g_CASE_FALL$ = g_CASE_FALL$ & "||"
								WEND
								WRITELN g_CASE_CONT$ & "if (", g_CASE_FALL$, "){" TO g_CFILE
								g_IN_CASE[g_SELECTVAR_CTR] = 1
								g_CASE_FALL$ = ""
							END IF
						ELSE
							exp$ = MID$(statement$, INSTR(statement$, "CASE") + 4)
							IF RIGHT$(statement$, 1) = ";" THEN
								g_CASE_FALL$ = g_CASE_FALL$ & "(" & g_SELECTVAR$[g_SELECTVAR_CTR] & ") == (" & LEFT$(exp$, LEN(exp$)-1) & ") ||"
							ELSE
								WHILE LEN(exp$)
									str$ = Mini_Parser$(exp$)
									g_CASE_FALL$ = g_CASE_FALL$ & "(" & g_SELECTVAR$[g_SELECTVAR_CTR] & ") == (" & str$ & ")"
									exp$ = MID$(exp$, LEN(str$)+2)
									IF LEN(exp$) THEN g_CASE_FALL$ = g_CASE_FALL$ & "||"
								WEND
								WRITELN g_CASE_CONT$ & "if (", g_CASE_FALL$, "){" TO g_CFILE
								g_IN_CASE[g_SELECTVAR_CTR] = 1
								g_CASE_FALL$ = ""
							END IF
						END IF
					END IF

				CASE "DEFAULT"
					IF ISTRUE(g_IN_CASE[g_SELECTVAR_CTR]) THEN
						WRITELN "} else {" TO g_CFILE
					ELSE
						EPRINT NL$, "Syntax error: cannot use DEFAULT without previous CASE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					END IF
					g_IN_CASE[g_SELECTVAR_CTR] = 0
					g_CASE_FALL$ = ""

				CASE "SETENVIRON"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty SETENVIRON at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Resolve this with C macro
						WRITELN "SETENVIRON(", MID$(statement$, INSTR(statement$, "SETENVIRON") + 10), ");" TO g_CFILE
					END IF

				CASE "SORT"
					Handle_Sort(statement$)

				CASE "STOP"
					' Check argument
					IF dim = 1 THEN
						WRITELN "kill(getpid(), SIGSTOP);" TO g_CFILE
					ELSE
						WRITELN "kill(getpid(),", EXTRACT$(MID$(statement$, INSTR(statement$, "STOP") + 4), CHR$(34)), ");" TO g_CFILE
					ENDIF

				CASE "TRACE"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty TRACE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						IF element$[2] = "MONITOR" THEN
							g_TRACE = 1
							WRITELN "fprintf(stderr, \"File '", g_CURFILE$, "' line %d: TRACE ON - press <SPACE> to execute the program step by step, <ESC> to exit.\\n\", ", g_COUNTER, ");" TO g_CFILE
							g_MONITOR$ = ""
							FOR sym$ IN MID$(statement$, INSTR(statement$, "MONITOR")+7) STEP ","
								sym$ = CHOP$(EXTRACT$(sym$,"\\(.*", TRUE))
								IF Check_String_Type(sym$) THEN
									exp$ = REPLACE$(sym$, g_STRINGSIGN$, "$")
									g_MONITOR$ = g_MONITOR$ & "&& (" & sym$ & "== NULL ? fprintf(stderr, \"MONITOR: " & exp$ & " = NULL\\n\") : fprintf(stderr, \"MONITOR: " & exp$ & " = %s\\n\", " & sym$ & ") )"
								ELSE
									exp$ = REPLACE$(sym$, g_FLOATSIGN$, "#")
									exp$ = REPLACE$(exp$, g_LONGSIGN$, "%")
									g_MONITOR$ = g_MONITOR$ & "&& fprintf(stderr, \"MONITOR: " & exp$ & " = %s\\n\", STR" & g_STRINGSIGN$ & "(" & sym$ & "))"
								ENDIF
							NEXT
						ELIF element$[2] = "ON" THEN
							g_TRACE = 1
							WRITELN "fprintf(stderr, \"File '", g_CURFILE$, "' line %d: TRACE ON - press <SPACE> to execute the program step by step, <ESC> to exit.\\n\", ", g_COUNTER, ");" TO g_CFILE
						ELIF element$[2] = "OFF" THEN
							g_MONITOR$ = ""
							g_TRACE = 0
						END IF
					ENDIF

				CASE "OPTION"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty OPTION at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						IF element$[2] = "BASE" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-9]") THEN
								g_OPTION_BASE = VAL(element$[3])
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION BASE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "COMPARE" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__option_compare = ", element$[3], ";" TO g_CFILE
								WRITELN "#undef __b2c__STRCMP" TO g_CFILE
								IF REGEX(element$[3], "1|TRUE") THEN
									WRITELN "#define __b2c__STRCMP __b2c__strcasecmp" TO g_CFILE
								ELSE
									WRITELN "#define __b2c__STRCMP __b2c__strcmp" TO g_CFILE
								ENDIF
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION COMPARE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "QUOTED" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__option_quoted = ", element$[3], ";" TO g_CFILE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION QUOTED at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "UTF8" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__option_utf8 = ", element$[3], ";" TO g_CFILE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION UTF8 at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "TLS" AND dim >= 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								IF element$[3] = "1" OR element$[3] = "TRUE" THEN
									g_OPTION_TLS = TRUE
									WRITELN "__b2c__option_tls = 1;" TO g_CFILE
									g_INC_TLS$ = "#include <openssl/ssl.h>" & NL$ & "#include <openssl/err.h>"
									g_LIB_TLS$ = CHOP$(EXEC$("pkg-config --libs openssl"))
								ELSE
									g_OPTION_TLS = FALSE
									WRITELN "__b2c__option_tls = 0;" TO g_CFILE
								ENDIF
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION TLS at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "EVAL" AND dim >= 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								g_CCFLAGS$ = g_CCFLAGS$ & " " & CHOP$(EXEC$("pkg-config --cflags libmatheval"))
								g_LDFLAGS$ = g_LDFLAGS$ & " " & CHOP$(EXEC$("pkg-config --libs libmatheval"))
								g_OPTION_EVAL = TRUE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION EVAL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "PROPER" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__option_proper = ", element$[3], ";" TO g_CFILE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION PROPER at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "ERROR" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__option_error = ", element$[3], ";" TO g_CFILE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION ERROR at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "DELIM" AND dim > 2 THEN
							WRITELN "__b2c__option_delim = ", MID$(statement$, INSTR(statement$, "DELIM") + 6), ";" TO g_CFILE
						ELIF element$[2] = "INPUT" AND dim > 2 THEN
							g_OPTION_INPUT$ = element$[3]
						ELIF element$[2] = "DQ" AND dim > 2 THEN
							WRITELN "__b2c__option_dq = ", MID$(statement$, INSTR(statement$, "DQ") + 3), "&255;" TO g_CFILE
						ELIF element$[2] = "ESC" AND dim > 2 THEN
							WRITELN "__b2c__option_esc = ", MID$(statement$, INSTR(statement$, "ESC") + 4), "&255;" TO g_CFILE
						ELIF element$[2] = "SOCKET" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-9]") THEN
								g_OPTION_SOCKET = VAL(element$[3])
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION SOCKET at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "BREAK" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								g_OPTION_BREAK = IIF(element$[3] = "TRUE", 1, VAL(element$[3]))
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION BREAK at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "MEMSTREAM" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__option_memstream = ", element$[3], ";" TO g_CFILE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION MEMSTREAM at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "MEMTYPE" AND dim > 2 THEN
							WRITELN "#undef __b2c__MEMTYPE" TO g_CFILE
							WRITELN "#define __b2c__MEMTYPE ", MID$(statement$, INSTR(statement$, "MEMTYPE")+8) TO g_CFILE
						ELIF element$[2] = "COLLAPSE" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__collapse = ", element$[3], ";" TO g_CFILE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION COLLAPSE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "DEVICE" AND dim >= 3 THEN
							WRITELN "__b2c__option_open = (", element$[3], ");" TO g_CFILE
						ELIF element$[2] = "STARTPOINT" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								WRITELN "__b2c__option_startpoint = ", element$[3], ";" TO g_CFILE
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION STARTPOINT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "INTERNATIONAL" AND dim = 3 THEN
							IF REGEX(element$[3], "1|TRUE") THEN
								WRITELN "#include <libintl.h>" TO g_HFILE
								WRITELN "setlocale(LC_ALL, \"\");" TO g_CFILE
								WRITELN "if(bindtextdomain(\"", LEFT$(g_SOURCEFILE$, INSTR(g_SOURCEFILE$, ".")-1), "\",\"/usr/share/locale\")==NULL){if(__b2c__trap){ERROR = 6; if(!__b2c__catch_set) RUNTIMEERROR(\"OPTION INTERNATIONAL\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
								WRITELN "if(textdomain(\"", LEFT$(g_SOURCEFILE$, INSTR(g_SOURCEFILE$, ".")-1), "\")==NULL){if(__b2c__trap){ERROR = 6; if(!__b2c__catch_set) RUNTIMEERROR(\"OPTION INTERNATIONAL\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
								IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION INTERNATIONAL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "NETWORK" AND dim >= 3 THEN
							SELECT element$[3]
								CASE "TCP"
									g_NETWORKTYPE$ = "TCP"
									g_SOCKTYPE$ = "SOCK_STREAM"
								CASE "UDP"
									g_NETWORKTYPE$ = "UDP"
									g_SOCKTYPE$ = "SOCK_DGRAM"
								CASE "BROADCAST"
									g_NETWORKTYPE$ = "BROADCAST"
									g_SOCKTYPE$ = "SOCK_DGRAM"
								CASE "MULTICAST"
									g_NETWORKTYPE$ = "MULTICAST"
									g_SOCKTYPE$ = "SOCK_DGRAM"
									IF dim = 4 AND REGEX(element$[4], "[0-9]") THEN
										g_MULTICAST_TTL = VAL(element$[4])
									ENDIF
								CASE "SCTP"
									g_INCFILES$ = g_INCFILES$ & " <netinet/sctp.h>"
									WRITELN "struct sctp_initmsg __b2c__initmsg;" TO g_HFILE
									g_NETWORKTYPE$ = "SCTP"
									g_SOCKTYPE$ = "SOCK_STREAM"
									g_LDFLAGS$ = g_LDFLAGS$ & " -lsctp"
									IF dim = 4 AND REGEX(element$[4], "[0-9]") THEN
										g_SCTP_STREAMS = VAL(element$[4])
									END IF
								DEFAULT
									EPRINT NL$, "Syntax error: invalid argument to OPTION NETWORK at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
									END 1
							END SELECT
						ELIF element$[2] = "PARSE" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								g_IGNORE_PARSE$ = element$[3]
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION PARSE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "EXPLICIT" AND dim = 3 THEN
							IF REGEX(element$[3], "[0-1]|TRUE|FALSE") THEN
								g_OPTION_EXPLICIT$ = element$[3]
							ELSE
								EPRINT NL$, "Syntax error: invalid argument to OPTION EXPLICIT at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
								END 1
							END IF
						ELIF element$[2] = "VARTYPE" AND dim > 2 THEN
							g_VARTYPE$ = MID$(statement$, INSTR(statement$, "VARTYPE")+8)
						ELIF element$[2] = "GUI" AND dim = 3 THEN
							IF REGEX(element$[3], "1|TRUE") THEN
								WRITELN "#define __b2c__gui_xaw" TO g_GENERIC
								WRITELN "#ifdef __b2c__gui_xaw" TO g_HFILE
								WRITELN "#include <AllWidgets.h>" TO g_HFILE
								WRITELN "#include <AsciiText.h>" TO g_HFILE
								WRITELN "#include <Box.h>" TO g_HFILE
								WRITELN "#include <Dialog.h>" TO g_HFILE
								WRITELN "#include <Command.h>" TO g_HFILE
								WRITELN "#include <Form.h>" TO g_HFILE
								WRITELN "#include <Grip.h>" TO g_HFILE
								WRITELN "#include <List.h>" TO g_HFILE
								WRITELN "#include <MenuButton.h>" TO g_HFILE
								WRITELN "#include <MultiSink.h>" TO g_HFILE
								WRITELN "#include <Paned.h>" TO g_HFILE
								WRITELN "#include <Panner.h>" TO g_HFILE
								WRITELN "#include <Porthole.h>" TO g_HFILE
								WRITELN "#include <Repeater.h>" TO g_HFILE
								WRITELN "#include <Scrollbar.h>" TO g_HFILE
								WRITELN "#include <SimpleMenu.h>" TO g_HFILE
								WRITELN "#include <SmeBSB.h>" TO g_HFILE
								WRITELN "#include <SmeLine.h>" TO g_HFILE
								WRITELN "#include <StripChart.h>" TO g_HFILE
								WRITELN "#include <Tip.h>" TO g_HFILE
								WRITELN "#include <Toggle.h>" TO g_HFILE
								WRITELN "#include <Tree.h>" TO g_HFILE
								WRITELN "#include <Viewport.h>" TO g_HFILE
								WRITELN "#include <X11/Intrinsic.h>" TO g_HFILE
								WRITELN "#include <X11/Shell.h>" TO g_HFILE
								WRITELN "#include <X11/StringDefs.h>" TO g_HFILE
								WRITELN "#endif" TO g_HFILE
								g_CCFLAGS$ = g_CCFLAGS$ & " -I/usr/include/X11/Xaw"
								g_INCLUDE_FILES$ = g_INCLUDE_FILES$ & " " & g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".gui.h"
								g_LDFLAGS$ =  g_LDFLAGS$ & " -lXaw -lXmu -lXt -lX11"
							ENDIF
						ELSE
							EPRINT NL$, "Syntax error: argument to OPTION at line ", g_COUNTER, " in file '", g_CURFILE$, "' not recognized!"
							END 1
						END IF
					END IF

				CASE "PROTO"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty PROTO at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						exp$ = MID$(EXTRACT$(statement$, CHR$(34)), INSTR(statement$, "PROTO") + 5)
						' Check if ALIAS is there
						IF INSTR(exp$, " ALIAS ") THEN
							WRITELN "#define ", MID$(exp$, INSTR(exp$, " ALIAS ") + 7), " ", MID$(exp$, 1, INSTR(exp$, " ALIAS ")) TO g_HFILE
							g_IMPORTED$ = MID$(exp$, INSTR(exp$, " ALIAS ") + 7) & " " & g_IMPORTED$
							g_IMPORTED$ = MID$(exp$, 1, INSTR(exp$, " ALIAS ")) & " " & g_IMPORTED$
						ELIF INSTR(exp$, " TYPE ") THEN
							WRITELN MID$(exp$, INSTR(exp$, " TYPE ") + 6), " ", MID$(exp$, 1, INSTR(exp$, " TYPE ")), ";" TO g_HFILE
						ELSE
							g_IMPORTED$ = REPLACE$(exp$, ",", " ") & " " & g_IMPORTED$
						END IF
					END IF

				CASE "INCR"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty INCR at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Get left side
						token$ = Mini_Parser$(statement$)
						' Get right side
						exp$ = CHOP$(MID$(statement$, LEN(token$)+2))
						IF NOT(LEN(exp$)) THEN exp$ = "1"
						token$ = CHOP$(MID$(token$, INSTR(token$, " ")))
						' Check if there is associative array assignment
						IF REGEX(token$, "[a-zA-Z]+\\(.*\\)$") THEN
							lft$ = LEFT$(token$, INSTR(token$, "(") - 1)
							str$ = INBETWEEN$(token$, "(", ")", 2)
							WRITELN "__b2c__assoc_", lft$, "_eval = ", token$, " + (", exp$, "); __b2c__hash_add(__b2c__assoc_", lft$, ", &__b2c__assoc_", lft$, "_eval, ", str$, ");" TO g_CFILE
							' Check for relations
							Relate_Recurse(lft$, str$, token$ & "+(" & exp$ & ")", -1)
						ELSE
							' Regular number
							IF REGEX(exp$, "[0-9]\\.[0-9]") THEN
								Register_Numeric(token$, TRUE)
							ELIF NOT(LEN(Get_Var$(token$, g_FUNCNAME$))) THEN
								Register_Numeric(token$, FALSE)
							ENDIF
							WRITELN token$, " = ", token$, " + (", exp$, ");" TO g_CFILE
						END IF
					END IF

				CASE "DECR"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty DECR at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Get left side
						token$ = Mini_Parser$(statement$)
						' Get right side
						exp$ = CHOP$(MID$(statement$, LEN(token$)+2))
						IF NOT(LEN(exp$)) THEN exp$ = "1"
						token$ = CHOP$(MID$(token$, INSTR(token$, " ")))
						' Check if there is associative array assignment
						IF REGEX(token$, "[a-zA-Z]+\\(.*\\)$") THEN
							lft$ = LEFT$(token$, INSTR(token$, "(") - 1)
							str$ = INBETWEEN$(token$, "(", ")", 2)
							WRITELN "__b2c__assoc_", lft$, "_eval = ", token$, " - (", exp$, "); __b2c__hash_add(__b2c__assoc_", lft$, ", &__b2c__assoc_", lft$, "_eval, ", str$, ");" TO g_CFILE
							' Check for relations
							Relate_Recurse(lft$, str$, token$ & "+(" & exp$ & ")", -1)
						ELSE
							' Regular number
							IF REGEX(exp$, "[0-9]\\.[0-9]") THEN
								Register_Numeric(token$, TRUE)
							ELIF NOT(LEN(Get_Var$(token$, g_FUNCNAME$))) THEN
								Register_Numeric(token$, FALSE)
							ENDIF
							WRITELN token$, " = ", token$, " - (", exp$, ");" TO g_CFILE
						END IF
					END IF

				CASE "ALARM"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty ALARM at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						str$ = EXTRACT$(TOKEN$(statement$, 1, ","), "^ALARM ", TRUE)
						exp$ = TOKEN$(statement$, 2, ",")
						WRITELN "__b2c__alarm((void*)(uintptr_t)(&", str$, "), ", exp$, ");" TO g_CFILE
					END IF

				CASE "SIGNAL"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty SIGNAL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Walk through commas
						SPLIT LAST$(statement$, 1) BY "," TO symbol$ SIZE dim
						IF dim = 2 THEN
							IF ISTOKEN(symbol$[1], "SIG_DFL") OR ISTOKEN(symbol$[1], "SIG_IGN") THEN
								WRITELN "__b2c__signal((void*)(uintptr_t)", symbol$[1], ", ", symbol$[2], ");" TO g_CFILE
							ELSE
								WRITELN "__b2c__signal((void*)(uintptr_t)(&", symbol$[1], "), ", symbol$[2], ");" TO g_CFILE
							ENDIF
						ELSE
							EPRINT NL$, "Syntax error: missing argument in SIGNAL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
							END 1
						END IF
					END IF

				CASE "CURSOR"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty CURSOR at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						exp$ = IIF$(dim = 3, element$[3], "1")
						IF element$[2] = "ON" THEN
							WRITELN "fprintf(stdout,\"\\033[?25h\"); fflush(stdout);" TO g_CFILE
						ELIF element$[2] = "OFF" THEN
							WRITELN "fprintf(stdout,\"\\033[?25l\"); fflush(stdout);" TO g_CFILE
						ELIF element$[2] = "UP" THEN
							WRITELN "fprintf(stdout,\"\\033[%ldA\", (long)", exp$, "); fflush(stdout);" TO g_CFILE
						ELIF element$[2] = "DOWN" THEN
							WRITELN "fprintf(stdout,\"\\033[%ldB\", (long)", exp$, "); fflush(stdout);" TO g_CFILE
						ELIF element$[2] = "FORWARD" THEN
							WRITELN "fprintf(stdout,\"\\033[%ldC\", (long)", exp$, "); fflush(stdout);" TO g_CFILE
						ELIF element$[2] = "BACK" THEN
							WRITELN "fprintf(stdout,\"\\033[%ldD\", (long)", exp$, "); fflush(stdout);" TO g_CFILE
						END IF
					ENDIF

				CASE "SCROLL"
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty SCROLL at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						exp$ = IIF$(dim = 3, element$[3], "1")
						IF element$[2] = "UP" THEN
							WRITELN "fprintf(stdout,\"\\033[%ldS\", (long)", exp$, "); fflush(stdout);" TO g_CFILE
						ELIF element$[2] = "DOWN" THEN
							WRITELN "fprintf(stdout,\"\\033[%ldT\", (long)", exp$, "); fflush(stdout);" TO g_CFILE
						END IF
					END IF

				CASE "ALIAS"
					Handle_Alias(statement$)

				CASE "LOOKUP"
					Handle_Lookup(statement$)

				CASE "RELATE"
					Handle_Relate(CHOP$(MID$(statement$, INSTR(statement$, "RELATE") + 6)))

				CASE "TEXTDOMAIN"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty TEXTDOMAIN at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						' Walk through commas
						SPLIT CHOP$(MID$(statement$, INSTR(statement$, "TEXTDOMAIN") + 10)) BY "," TO symbol$ SIZE dim
						IF dim = 2 THEN
							WRITELN "if(bindtextdomain(", symbol$[1], ",", symbol$[2], ")==NULL){if(__b2c__trap){ERROR = 6; if(!__b2c__catch_set) RUNTIMEERROR(\"TEXTDOMAIN\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
							WRITELN "if(textdomain(", symbol$[1], ")==NULL){if(__b2c__trap){ERROR = 6; if(!__b2c__catch_set) RUNTIMEERROR(\"TEXTDOMAIN\", ", g_COUNTER, ", \"", g_CURFILE$, "\", ERROR); else if(!setjmp(__b2c__jump)) goto ", g_CATCHGOTO$, ";} }" TO g_CFILE
							IF g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT" THEN g_CATCH_USED = 1
						ELSE
							EPRINT NL$, "Syntax error: missing argument in TEXTDOMAIN at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
							END 1
						END IF
					END IF

				CASE "REDIM"
					Handle_Redim(CHOP$(MID$(statement$, INSTR(statement$, "REDIM") + 5)))

				CASE "EXIT"
					IF LEN(g_FUNCNAME$) = 0 THEN
						EPRINT NL$, "Syntax error: EXIT not in FUNCTION or SUB at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					END IF
					' Free strings variables if there are any
					WRITELN g_STRINGARRAYS$ TO g_CFILE
					FOR exp$ IN g_LOCALSTRINGS$
						WRITELN "__b2c__STRFREE(", exp$, ");" TO g_CFILE
					NEXT
					WRITELN "__b2c__catch_set = __b2c__catch_set_backup;" TO g_CFILE
					' The actual exit
					IF INSTR(g_FUNCNAME$, g_STRINGSIGN$) THEN
						WRITELN "return(NULL);" TO g_CFILE
					ELSE
						WRITELN "return __b2c__exitval;" TO g_CFILE
					END IF

				CASE "PRAGMA"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty PRAGMA at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						IF element$[2] = "OPTIONS" AND dim >= 3 THEN
							FOR i = 3 TO dim
								g_CCFLAGS$ = g_CCFLAGS$ & " " & element$[i]
							NEXT
						ELIF element$[2] = "COMPILER" AND dim = 3 THEN
							g_CCNAME$ = element$[3]
						ELIF element$[2] = "FRAMEWORK" AND dim >= 3 THEN
							FOR i = 3 TO dim
								g_LDFLAGS$ = g_LDFLAGS$ & " -framework " & element$[i]
							NEXT
						ELIF element$[2] = "RE" AND dim >= 3 THEN
							g_PRAGMA_REGEX$ = MID$(statement$, INSTR(statement$, "RE")+3)
							IF NOT(REGEX(g_PRAGMA_REGEX$, " LDFLAGS ")) THEN
								exp$ = HEAD$(g_PRAGMA_REGEX$, 1)
								IF INSTR(exp$, "tre") THEN
									g_LDFLAGS$ = g_LDFLAGS$ & " " & CHOP$(EXEC$("pkg-config --libs tre"))
								ELIF INSTR(exp$, "pcre") THEN
									g_LDFLAGS$ = g_LDFLAGS$ & " " & CHOP$(EXEC$("pkg-config --libs libpcreposix"))
								ELIF INSTR(exp$, "onig") THEN
									g_LDFLAGS$ = g_LDFLAGS$ & " " & CHOP$(EXEC$("pkg-config --libs oniguruma"))
								ENDIF
							ELSE
								exp$ = MID$(g_PRAGMA_REGEX$, INSTR(g_PRAGMA_REGEX$, " LDFLAGS ")+9)
								g_LDFLAGS$ = exp$ & " " & g_LDFLAGS$
							ENDIF
						ELIF element$[2] = "TLS" AND dim >= 3 THEN
							g_LIB_TLS$ = MID$(statement$, INSTR(statement$, "TLS")+4)
							IF NOT(REGEX(g_LIB_TLS$, " LDFLAGS ")) THEN
								exp$ = HEAD$(g_LIB_TLS$, 1)
								IF TALLY(exp$, "openssl") THEN
									g_LIB_TLS$ = CHOP$(EXEC$("pkg-config --libs openssl"))
									g_INC_TLS$ = "#include <openssl/ssl.h>" & NL$ & "#include <openssl/err.h>"
								ELIF TALLY(exp$, "gnutls") THEN
									g_LIB_TLS$ = CHOP$(EXEC$("pkg-config --libs gnutls")) & " -lgnutls-openssl"
									g_INC_TLS$ = "#include <gnutls/openssl.h>" & NL$ & "#define TLS_client_method TLSv1_client_method" & NL$ & "#define TLS_server_method TLSv1_server_method"
								ELIF INSTR(exp$, "wolfssl") THEN
									g_LIB_TLS$ = CHOP$(EXEC$("pkg-config --libs wolfssl"))
									g_INC_TLS$ = "#include <wolfssl/options.h>" & NL$ & "#include <wolfssl/openssl/ssl.h>"
								ENDIF
							ELSE
								g_INC_TLS$ = LEFT$(g_LIB_TLS$, INSTR(g_LIB_TLS$, " LDFLAGS ")-1)
								g_LIB_TLS$ = MID$(g_LIB_TLS$, INSTR(g_LIB_TLS$, " LDFLAGS ")+9)
							ENDIF
						ELIF element$[2] = "GUI" AND dim >= 3 THEN
							exp$ = MID$(statement$, INSTR(statement$, "GUI")+4)
							IF NOT(INSTR(exp$, " LDFLAGS ")) THEN
								IF LCASE$(HEAD$(exp$, 1)) = "xaw3d" THEN
									WRITELN "#include <ThreeD.h>" TO g_HFILE
									g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw", "-lXaw3d")
									g_CCFLAGS$ = REPLACE$(g_CCFLAGS$, "-I/usr/include/X11/Xaw", "-I/usr/include/X11/Xaw3d")
								ELIF LCASE$(HEAD$(exp$, 1)) = "motif" THEN
									WRITELN "#undef __b2c__gui_xaw" TO g_GENERIC
									WRITELN "#include <Xm/XmAll.h>" TO g_HFILE
									g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw", "-lXm")
									g_CCFLAGS$ = EXTRACT$(g_CCFLAGS$, "-I/usr/include/X11/Xaw")
								ELIF LCASE$(HEAD$(exp$, 1)) = "uil" THEN
									WRITELN "#undef __b2c__gui_xaw" TO g_GENERIC
									WRITELN "#define __b2c__gui_uil" TO g_GENERIC
									WRITELN "#include <Xm/XmAll.h>" TO g_HFILE
									WRITELN "#include <Mrm/MrmAppl.h>" TO g_HFILE
									g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw", "-lMrm -lXm")
									g_CCFLAGS$ = EXTRACT$(g_CCFLAGS$, "-I/usr/include/X11/Xaw")
								ELIF LCASE$(HEAD$(exp$, 1)) = "gtk2" THEN
									WRITELN "#undef __b2c__gui_xaw" TO g_GENERIC
									WRITELN "#include <gtk/gtk.h>" TO g_HFILE
									g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw -lXmu -lXt -lX11", "`pkg-config --libs gtk+-2.0`")
									g_CCFLAGS$ = REPLACE$(g_CCFLAGS$, "-I/usr/include/X11/Xaw", "`pkg-config --cflags gtk+-2.0`")
									g_WHICH_GUI = 1
								ELIF LCASE$(HEAD$(exp$, 1)) = "gtk3" THEN
									WRITELN "#undef __b2c__gui_xaw" TO g_GENERIC
									WRITELN "#include <gtk/gtk.h>" TO g_HFILE
									g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw -lXmu -lXt -lX11", "`pkg-config --libs gtk+-3.0`")
									g_CCFLAGS$ = REPLACE$(g_CCFLAGS$, "-I/usr/include/X11/Xaw", "`pkg-config --cflags gtk+-3.0`")
									g_WHICH_GUI = 1
								ELIF LCASE$(HEAD$(exp$, 1)) = "gtk4" THEN
									WRITELN "#undef __b2c__gui_xaw" TO g_GENERIC
									WRITELN "#include <gtk/gtk.h>" TO g_HFILE
									g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw -lXmu -lXt -lX11", "`pkg-config --libs gtk4`")
									g_CCFLAGS$ = REPLACE$(g_CCFLAGS$, "-I/usr/include/X11/Xaw", "`pkg-config --cflags gtk4`")
									g_WHICH_GUI = 3
								ELIF LCASE$(HEAD$(exp$, 1)) = "cdk" THEN
									WRITELN "#undef __b2c__gui_xaw" TO g_GENERIC
									WRITELN "#include <cdk.h>" TO g_HFILE
									g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw -lXmu -lXt -lX11", "-lncurses -lcdk")
									g_CCFLAGS$ = REPLACE$(g_CCFLAGS$, "-I/usr/include/X11/Xaw", "-I/usr/include/cdk")
									g_WHICH_GUI = 2
								ENDIF
								IF g_WHICH_GUI = 1 THEN
									WRITELN "#define GTKINIT gtk_init(NULL,NULL)" TO g_HFILE
									WRITELN "#define GTKMAINITERATION gtk_main_iteration()" TO g_HFILE
									WRITELN "#define GTKWIDGETSHOW gtk_widget_show_all" TO g_HFILE
									WRITELN "#define GTKCONTAINERADD(x,y) gtk_container_add(GTK_CONTAINER(x), GTK_WIDGET(y))" TO g_HFILE
								ELIF g_WHICH_GUI = 3 THEN
									WRITELN "#define GTKINIT gtk_init()" TO g_HFILE
									WRITELN "#define GTKMAINITERATION g_main_context_iteration(NULL,1)" TO g_HFILE
									WRITELN "#define GTKWIDGETSHOW gtk_widget_show" TO g_HFILE
									WRITELN "#define GTKCONTAINERADD(x,y) (GTK_IS_BOX(x) ? gtk_box_append(GTK_BOX(x), GTK_WIDGET(y)) : g_object_set(GTK_WIDGET(x), \"child\", GTK_WIDGET(y), NULL))" TO g_HFILE
								ENDIF
							ELSE
								g_LDFLAGS$ = REPLACE$(g_LDFLAGS$, "-lXaw", TOKEN$(exp$, 2, " LDFLAGS "))
								g_CCFLAGS$ = REPLACE$(g_CCFLAGS$, "-I/usr/include/X11/Xaw", TOKEN$(TOKEN$(exp$, 1, " LDFLAGS "), 2, " OPTIONS "))
							ENDIF
						ELIF element$[2] = "LDFLAGS" AND dim >= 3 THEN
							IF TALLY(TOKEN$(statement$, 2, "LDFLAGS"), "pkg-config") THEN
								g_LDFLAGS$ = TOKEN$(statement$, 2, "LDFLAGS") & " " & g_LDFLAGS$
							ELSE
								FOR i = 3 TO dim
									IF element$[i] = "TRUE" THEN
										found = TRUE
										BREAK
									ELIF LEFT$(element$[i], 1) = "-" OR RIGHT$(element$[i], 2) = ".a" THEN
										exp$ = exp$ & " " & element$[i]
									ELSE
										exp$ = exp$ & " -l" & element$[i]
									FI
								NEXT
								IF found THEN
									g_LDFLAGS$ = exp$ & " " & g_LDFLAGS$
								ELSE
									g_LDFLAGS$ = g_LDFLAGS$ & " " & exp$
								FI
							FI
						ELIF element$[2] = "INCLUDE" AND dim >= 3 THEN
							FOR i = 3 TO dim
								IF LEFT$(element$[i], 1) = "/" OR LEFT$(element$[i], 2) = "./" THEN
									g_PRAGMA_INCLUDE$ = g_PRAGMA_INCLUDE$ & NL$ & "#include " & CHR$(34) & element$[i] & CHR$(34)
								ELIF LEFT$(element$[i], 1) = "<" THEN
									g_PRAGMA_INCLUDE$ = g_PRAGMA_INCLUDE$ & NL$ & "#include " & element$[i]
								ELSE
									g_PRAGMA_INCLUDE$ = g_PRAGMA_INCLUDE$ & NL$ & "#include " & CHR$(34) & CURDIR$ & "/" & element$[i] & CHR$(34)
								ENDIF
							NEXT
						ELSE
							WRITELN "#pragma ", CHOP$(MID$(statement$, INSTR(statement$, "PRAGMA") + 6)) TO g_CFILE
						END IF
					ENDIF

				CASE "SWAP"
					Handle_Swap(statement$)

				CASE "SETSERIAL"
					Handle_Setserial(CHOP$(MID$(statement$, INSTR(statement$, "SETSERIAL") + 9)))

				CASE "ENUM"
					IF NOT(LEN(g_FUNCNAME$)) THEN
						WRITELN "enum {" TO g_HFILE
						g_USE_H = 1
					ELSE
						WRITELN "enum {" TO g_CFILE
						g_USE_C = 1
					ENDIF

				CASE "RUN"
					Handle_Run(CHOP$(MID$(statement$, INSTR(statement$, "RUN") + 3)))

				CASE "SAVE"
					Handle_Save(0, CHOP$(MID$(statement$, INSTR(statement$, "SAVE") + 4)))

				CASE "BSAVE"
					Handle_Save(1, CHOP$(MID$(statement$, INSTR(statement$, "BSAVE") + 5)))

				CASE "APPEND"
					exp$ = MID$(statement$, INSTR(statement$, "APPEND") + 6)
					IF NOT(ISTOKEN(exp$, "TO")) AND HASDELIM(exp$, ",") THEN
						WRITELN TOKEN$(exp$, 1, ","), "= CONCAT", g_STRINGSIGN$, "(", exp$, ");" TO g_CFILE
					ELSE
						Handle_Save(2, CHOP$(MID$(statement$, INSTR(statement$, "APPEND") + 6)))
					FI

				CASE "BAPPEND"
					Handle_Save(3, CHOP$(MID$(statement$, INSTR(statement$, "BAPPEND") + 7)))

				CASE "MAP"
					Handle_Map(statement$)

				CASE "RESET"
					WRITELN "fprintf(stdout,\"\\033c\"); fflush(stdout);" TO g_CFILE

				CASE "CERTIFICATE"
					' Check argument
					IF dim = 1 THEN
						EPRINT NL$, "Syntax error: empty CERTIFICATE at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ELSE
						exp$ = MID$(statement$, INSTR(statement$, "CERTIFICATE") + 11)
						token$ = Mini_Parser$(exp$)
						WRITELN "#undef __b2c__caprivate" TO g_CFILE
						WRITELN "#define __b2c__caprivate ", token$ TO g_CFILE
						exp$ = MID$(exp$, LEN(token$)+2)
						token$ = Mini_Parser$(exp$)
						WRITELN "#undef __b2c__caserver" TO g_CFILE
						WRITELN "#define __b2c__caserver ", token$ TO g_CFILE
					ENDIF

				CASE "TREE"
					Handle_Tree(statement$)

				CASE "COLLECT"
					Handle_Collect(statement$)

				CASE "PARSE"
					Handle_Parse(statement$)

				DEFAULT
					' Check on imported symbols first
					IF INSTR(element$[1], "(") THEN element$[1] = TOKEN$(element$[1], 1, "(")

					IF ISTOKEN(g_IMPORTED$, element$[1]) THEN
						IF REGEX(statement$, "\\(.*\\)") THEN
							WRITELN statement$, ";" TO g_CFILE
						ELSE
							WRITELN statement$, "();" TO g_CFILE
						ENDIF
					ELSE
						Handle_Let(statement$)
					ENDIF
			ENDSELECT
		END IF
	END IF

END SUB

'----------------------------------------------------------------------------------------------

FUNCTION Pre_Tokenize_Functions$(arg$)

	LOCAL token$, it$, var$, val$, type$, first$, second$, delim$, intoken$
	LOCAL is_escaped, is_string, i, j, mem, nr = 1, many, pos
	LOCAL out TYPE FILE*
	LOCAL cmd$[] = { "TYPEOF$", "SOURCE$", "OBTAIN$", "IIF(", "IIF$(", "FIND(", "EVAL(", "VERIFY", "REM", "LOOP", "COIL$", "GUIDEFINE", "UBOUND", "INDEX(" }

	' Check if one of these functions are there
	IF LOOP(UBOUND(cmd$), IIF(INSTR(arg$, cmd$[_]), 1, 0) ) THEN

		' If so, see if they are not part of a string and perform special treatment
		FOR i = 1 TO LEN(arg$)
			IF NOT(is_string) THEN
				IF MID$(arg$, i, 7) = "TYPEOF$" THEN
					it$ = MID$(arg$, i, INSTR(MID$(arg$, i), ")")-1)
					token$ = token$ & CHR$(34) & Get_Var$(MID$(it$, INSTR(it$, "(")+1), g_FUNCNAME$) & CHR$(34)
					INCR i, LEN(it$)+1
				ELIF MID$(arg$, i, 7) = "SOURCE$" THEN
					IF NOT(FILEEXISTS(SRCARRAYFILE$)) THEN
						mem = BLOAD(g_SOURCEFILE$)
						OPTION MEMTYPE unsigned char
						OPEN SRCARRAYFILE$ FOR WRITING AS out
						WRITELN "unsigned char SOURCE", g_STRINGSIGN$, "[]={"; TO out
						FOR j = 0 TO FILELEN(g_SOURCEFILE$)-1
							IF MOD(j, 16) = 0 THEN WRITELN "" TO out
							WRITELN PEEK(mem+j), ","; TO out
						NEXT
						WRITELN "0 };" TO out
						CLOSE FILE out
						FREE mem
					ENDIF
				ELIF MID$(arg$, i, 7) = "OBTAIN$" THEN
					pos = INSTR(MID$(arg$, i), "(")
					intoken$ = Mini_Parser$(MID$(arg$, i+pos))
					intoken$ = REPLACE$(intoken$, "$", g_STRINGSIGN$)
					intoken$ = REPLACE$(intoken$, "#", g_FLOATSIGN$)
					intoken$ = REPLACE$(intoken$, "%", g_LONGSIGN$)
					type$ = Get_Var$("__b2c__assoc_" & intoken$, g_FUNCNAME$)
					WRITELN "#undef __b2c__obtain_type_", intoken$ TO g_CFILE
					SELECT type$
						CASE "char*", "STRING"
							WRITELN "#define __b2c__obtain_type_", intoken$, " 0" TO g_CFILE
						CASE "double", "FLOATING"
							WRITELN "#define __b2c__obtain_type_", intoken$, " 1" TO g_CFILE
						CASE "float"
							WRITELN "#define __b2c__obtain_type_", intoken$, " 2" TO g_CFILE
						CASE "long", "NUMBER"
							WRITELN "#define __b2c__obtain_type_", intoken$, " 3" TO g_CFILE
						CASE "int"
							WRITELN "#define __b2c__obtain_type_", intoken$, " 4" TO g_CFILE
						CASE "short"
							WRITELN "#define __b2c__obtain_type_", intoken$, " 5" TO g_CFILE
						CASE "char"
							WRITELN "#define __b2c__obtain_type_", intoken$, " 6" TO g_CFILE
						DEFAULT
							WRITELN "#define __b2c__obtain_type_", intoken$, " -1" TO g_CFILE
					ENDSELECT
					token$ = token$ & "OBTAIN$"
					INCR i, 7
				ELIF MID$(arg$, i, 7) = "VERIFY(" THEN
					var$ = MID$(arg$, INSTR(arg$, "(")+1)
					intoken$ = Mini_Parser$(var$)
					intoken$ = MID$(var$, LEN(intoken$)+2)
					WRITELN "#undef __b2c__cacerts" TO g_HFILE
					WRITELN "#define __b2c__cacerts ", TOKEN$(intoken$, 1, ")") TO g_HFILE
					IF TALLY(g_LIB_TLS$, "wolfssl") THEN
						WRITELN "#undef __b2c__capeer" TO g_HFILE
						WRITELN "#define __b2c__capeer SSL_VERIFY_PEER" TO g_HFILE
					ENDIF
					token$ = token$ & "VERIFY("
					INCR i, 7
				ELIF MID$(arg$, i, 6) = "UBOUND" THEN
					it$ = MID$(arg$, i, INSTR(MID$(arg$, i), ")")-1)
					INCR i, LEN(it$)+1
					it$ = REPLACE$(it$, "$", g_STRINGSIGN$)
					it$ = REPLACE$(it$, "#", g_FLOATSIGN$)
					it$ = REPLACE$(it$, "%", g_LONGSIGN$)
					IF LEN(Get_Var$("__b2c__assoc_" & TOKEN$(it$, 2, "("), g_FUNCNAME$)) THEN
						token$ = token$ & "NRKEYS(" & TOKEN$(it$, 2, "(") & ")"
					ELIF ISTOKEN(g_DYNAMICARRAYS$, TOKEN$(it$, 2, "(") & "@" & g_FUNCNAME$) THEN
						token$ = token$ & TOKEN$(it$, 2, "(") & "__b2c_array"
					ELSE
						type$ = Get_Var$(TOKEN$(it$, 2, "("), g_FUNCNAME$)
						token$ = token$ & "(sizeof(" & TOKEN$(it$, 2, "(") & ")/sizeof(" & type$ & ")-" & STR$(g_OPTION_BASE) & ")"
					ENDIF
				ELIF MID$(arg$, i, 6) = "INDEX(" THEN
					pos = INSTR(MID$(arg$, i), "(")
					intoken$ = Mini_Parser$(MID$(arg$, i+pos))
					type$ = Get_Var$(intoken$, g_FUNCNAME$)
					SELECT type$
						CASE "char*", "STRING"
							nr = 0
						CASE "double", "FLOATING"
							nr = 1
						CASE "float"
							nr = 2
						CASE "long", "NUMBER"
							nr = 3
						CASE "int"
							nr = 4
						CASE "short"
							nr = 5
						CASE "char"
							nr = 6
						DEFAULT
							nr = -1
					ENDSELECT
					intoken$ = REPLACE$(intoken$, "$", g_STRINGSIGN$)
					intoken$ = REPLACE$(intoken$, "#", g_FLOATSIGN$)
					intoken$ = REPLACE$(intoken$, "%", g_LONGSIGN$)
					IF ISTOKEN(g_DYNAMICARRAYS$, intoken$ & "@" & g_FUNCNAME$) THEN
						token$ = token$ & "INDEX(" & intoken$ & "__b2c_array," & STR$(nr) & ","
					ELSE
						type$ = Get_Var$(intoken$, g_FUNCNAME$)
						token$ = token$ & "INDEX(sizeof(" & intoken$ & ")/sizeof(" & type$ & ")-" & STR$(g_OPTION_BASE) & "," & STR$(nr) & ","
					ENDIF
					INCR i, 6
				ELIF MID$(arg$, i, 9) = "GUIDEFINE" THEN
					pos = INSTR(MID$(arg$, i), "(")
					intoken$ = Mini_Parser$(MID$(arg$, i+pos))
					CALL guiGenerate(CHOP$(intoken$, "\n\r\t " & CHR$(34)))
					token$ = token$ & "GUIDEFINE"
					INCR i, 9
				ELIF MID$(arg$, i, 6) = "LOOP$(" OR MID$(arg$, i, 6) = "COIL$(" OR MID$(arg$, i, 5) = "LOOP(" THEN
					delim$ = "__b2c__option_delim"
					pos = INSTR(MID$(arg$, i), "(")
					first$ = Mini_Parser$(MID$(arg$, i+pos))
					second$ = Mini_Parser$(MID$(arg$, i+pos+LEN(first$)+1))
					IF MID$(arg$, i+pos+LEN(first$)+1+LEN(second$), 1) = "," THEN
						intoken$ = Mini_Parser$(MID$(arg$, i+pos+LEN(first$)+1+LEN(second$)+1))
						IF MID$(arg$, i+pos+LEN(first$)+1+LEN(second$)+1+LEN(intoken$), 1) = "," THEN
							delim$ = Mini_Parser$(MID$(arg$, i+pos+LEN(first$)+1+LEN(second$)+1+LEN(intoken$)+1))
						ENDIF
					ELSE
						intoken$ = second$
						second$ = first$
						first$ = "_"
					ENDIF
					IF INSTR(intoken$, "LOOP") OR INSTR(intoken$, "COIL$") OR TALLY(arg$, "LOOP") > 1 OR TALLY(arg$, "COIL$") > 1 THEN
						EPRINT NL$, "Syntax error: multiple LOOP$/COIL$/LOOP functions in one statement at line ", g_COUNTER, " in file '", g_CURFILE$, "'!"
						END 1
					ENDIF
					IF MID$(arg$, i, pos) = "LOOP$(" THEN
						token$ = Pre_Tokenize_Functions$("IF setjmp(__b2c__loop2) THEN:FOR " & first$ & "=1 TO " & second$ & ":__b2c__loop_result$ = CONCAT$(__b2c__loop_result$, " & intoken$ & "):NEXT:CALL longjmp(__b2c__loop1, 1):ENDIF:" & token$)
					ELIF MID$(arg$, i, pos) = "COIL$(" THEN
						token$ = Pre_Tokenize_Functions$("IF setjmp(__b2c__loop2) THEN:FOR " & first$ & "=1 TO " & second$ & ":__b2c__loop_result$ = APPEND$(__b2c__loop_result$, 0, " & intoken$ & "," & delim$ & "):NEXT:CALL longjmp(__b2c__loop1, 1):ENDIF:" & token$)
					ELSE
						token$ = Pre_Tokenize_Functions$("IF setjmp(__b2c__loop2) THEN:FOR " & first$ & "=1 TO " & second$ & ":__b2c__loop_result = __b2c__loop_result + (" & intoken$ & "):NEXT:CALL longjmp(__b2c__loop1, 1):ENDIF:" & token$)
					ENDIF
				ELIF MID$(arg$, i, 4) = "IIF(" THEN
					intoken$ = Mini_Parser$(MID$(arg$, i+4))
					IF REGEX(arg$, ".* " & g_RANGEOP$ & ".*;.*") THEN intoken$ = intoken$ & ";" & Mini_Parser$(MID$(arg$, i+4+LEN(intoken$)+1))
					INCR i, 4+LEN(intoken$)
					token$ = token$ & "IIF(" & Pre_Tokenize_Functions$(Parse_Equation$(intoken$))
				ELIF MID$(arg$, i, 5) = "IIF$(" THEN
					intoken$ = Mini_Parser$(MID$(arg$, i+5))
					IF REGEX(arg$, ".* " & g_RANGEOP$ & ".*;.*") THEN intoken$ = intoken$ & ";" & Mini_Parser$(MID$(arg$, i+5+LEN(intoken$)+1))
					INCR i, 5+LEN(intoken$)
					token$ = token$ & "IIF$(" & Pre_Tokenize_Functions$(Parse_Equation$(intoken$))
				ELIF MID$(arg$, i, 5) = "EVAL(" THEN
					IF nr = 1 THEN
						var$ = "char *__b2c_evalvars_" & g_FUNCNAME$ & "_" & STR$(g_COUNTER) & "_" & STR$(HASH(token$)>>8) & "[] = {"
						val$ = "double __b2c_evalvals_" & g_FUNCNAME$ & "_" & STR$(g_COUNTER) & "_" & STR$(HASH(token$)>>8) & "[] = {"
						LOOKUP g_ALL_FUNC_VARS$ TO funcvar$ SIZE many
						FOR j = 1 TO many
							IF TOKEN$(funcvar$[j], 2) = g_FUNCNAME$ THEN
								type$ = Get_Var$(TOKEN$(funcvar$[j], 1), g_FUNCNAME$)
								IF NOT(TALLY(type$, "*")) AND REGEX(type$, "double$|FLOATING$") THEN
									var$ = var$ & CHR$(34) & TOKEN$(funcvar$[j], 1) & CHR$(34) & ","
									val$ = val$ & TOKEN$(funcvar$[j], 1) & ","
									INCR nr
								ENDIF
							ENDIF
						NEXT
						LOOKUP g_ALL_MAIN_VARS$ TO mainvar$ SIZE many
						FOR j = 1 TO many
							type$ = Get_Var$(mainvar$[j])
							IF NOT(TALLY(type$, "*")) AND REGEX(type$, "double$|FLOATING$") THEN
								var$ = var$ & CHR$(34) & TOKEN$(mainvar$[j], 1) & CHR$(34) & ","
								val$ = val$ & TOKEN$(mainvar$[j], 1) & ","
								INCR nr
							ENDIF
						NEXT
						WRITELN var$, " NULL};" TO g_CFILE
						WRITELN val$, " 0};" TO g_CFILE
					ENDIF
					INCR i, 5
					token$ = token$ & "EVAL(__b2c_evalvars_" & g_FUNCNAME$ & "_" & STR$(g_COUNTER) & "_" & STR$(HASH(token$)>>8) & ",__b2c_evalvals_" & g_FUNCNAME$ & "_" & STR$(g_COUNTER) & "_" & STR$(HASH(token$)>>8) & "," & STR$(nr) & "-1,"
				ELIF MID$(arg$, i, 5) = "FIND(" THEN
					pos = INSTR(MID$(arg$, i), "(")
					intoken$ = Mini_Parser$(MID$(arg$, i+pos))
					intoken$ = REPLACE$(intoken$, "$", g_STRINGSIGN$)
					intoken$ = REPLACE$(intoken$, "#", g_FLOATSIGN$)
					intoken$ = REPLACE$(intoken$, "%", g_LONGSIGN$)
					type$ = Get_Var$("__b2c__tree_" & intoken$, g_FUNCNAME$)
					token$ = token$ & "FIND(" & type$ & ","
					INCR i, 5
				ELIF REGEX(MID$(arg$, i, 4), "REM[[:space:]]") OR arg$ = "REM" THEN
					BREAK
				ENDIF
			ENDIF
			SELECT ASC(MID$(arg$, i, 1))
					' Escape symbol
				CASE 92
					token$ = token$ & CHR$(92)
					is_escaped = NOT(is_escaped)
					' Quote symbol
				CASE 34
					token$ = token$ & CHR$(34)
					IF NOT(is_escaped) THEN is_string = NOT(is_string)
					is_escaped = FALSE
				DEFAULT
					token$ = token$ & MID$(arg$, i, 1)
					is_escaped = FALSE
			ENDSELECT
		NEXT
	ELSE
		token$ = arg$
	END IF

	RETURN token$

END FUNCTION

'----------------------------------------------------------------------------------------------

SUB Tokenize(STRING current$)

	LOCAL i, is_string, is_escaped, in_func
	LOCAL token$, item1$, item2$, result$, element$, txt$, elem$, sep$, str$, exp$
	LOCAL j, in_str, in_spac, bracket, direct, inescaped, isquote, sftot

	' Verify if there is a class definition or we are in a (multiline) comment
	IF LEFT$(current$, 5) = "CLASS" OR g_COMMENT = TRUE THEN
		Parse_Line(CHOP$(current$))
		EXIT SUB
	ENDIF

	' In TRACE MODE show linenr and code
	IF g_TRACE = 1 THEN
		IF NOT(REGEX(CHOP$(current$), "^FUNCTION|^SUB|^ELIF|^ELSE")) AND NOT(LEN(g_TRACE_PREFIX$)) THEN
			WRITELN "if(__b2c__getch() == 27) {fprintf(stderr, \"TRACE OFF - exiting trace mode.\\n\"); exit(EXIT_SUCCESS);}" TO g_CFILE
			txt$ = REPLACE$(current$, CHR$(34) & CHR$(92), CHR$(39) & CHR$(47), 2)
			WRITELN "fprintf(stderr, \"File '", g_CURFILE$, "' line %d: ", txt$, "\\n\", ", g_COUNTER, ");" TO g_CFILE
			IF LEN(g_MONITOR$) THEN WRITELN CHOP$(g_MONITOR$, "&&"), ";" TO g_CFILE
		ENDIF
		g_TRACE_PREFIX$ = ""
	END IF

	' See if there are special functions which need adjustments during conversion time
	current$ = Pre_Tokenize_Functions$(current$)

	WHILE TRUE
		' Initialize parser
		in_func=0
		is_string = FALSE
		is_escaped = FALSE
		token$ = ""

		' See if there are colons
		FOR i = 1 TO LEN(current$)
			SELECT ASC(MID$(current$, i, 1))
					' Separator
				CASE 58
					IF NOT(is_string) AND ASC(MID$(current$, i+1, 1)) = 58 THEN
						INCR i
						token$ = token$ & "::"
					ELIF NOT(is_string) AND ISFALSE(g_USE_C) AND ISFALSE(g_USE_H) AND NOT(in_func) THEN
						Parse_Line(CHOP$(token$))
						token$ = ""
					ELSE
						token$ = token$ & ":"
					END IF
					' Tab
				CASE 9
					token$ = token$ & IIF$(NOT(is_string), CHR$(32), CHR$(9))
					' String symbol
				CASE 36
					IF NOT(is_string) OR MATCH(current$, "IMPORT * FROM * TYPE *") THEN
						token$ = token$ & g_STRINGSIGN$
						is_escaped = FALSE
					ELSE
						token$ = token$ & "$"
					END IF
					' Bracket open symbol
				CASE 40
					IF NOT(is_string) AND ISFALSE(g_USE_C) AND ISFALSE(g_USE_H) THEN
						INCR in_func
					ENDIF
					token$ = token$ & CHR$(40)
					' Bracket close symbol
				CASE 41
					IF NOT(is_string) AND ISFALSE(g_USE_C) AND ISFALSE(g_USE_H) THEN DECR in_func
					token$ = token$ & CHR$(41)
					' Question mark
				CASE 63
					IF NOT(is_string) AND ISFALSE(g_USE_C) AND ISFALSE(g_USE_H) AND NOT(in_func) THEN token$ = token$ & "PRINT "
					ELSE token$ = token$ & CHR$(63)
					' Square bracket
				CASE 91
					IF NOT(is_string) AND MID$(current$, i, 2) <> "[]" AND MID$(current$, i, 11) <> "[(uint64_t)" THEN token$ = token$ & "[(uint64_t)"
					ELSE token$ = token$ & CHR$(91)
					' Long symbol
				CASE 37
					IF NOT(is_string) AND REGEX(RIGHT$(token$, 1), "[a-zA-Z0-9_]+") THEN
						token$ = token$ & g_LONGSIGN$
						is_escaped = FALSE
					ELSE
						token$ = token$ & "%"
					END IF
					' Float symbol
				CASE 35
					IF NOT(is_string) AND REGEX(RIGHT$(token$, 1), "[a-zA-Z0-9_]+") AND i > 1 THEN
						token$ = token$ & g_FLOATSIGN$
						is_escaped = FALSE
					ELSE
						token$ = token$ & "#"
					END IF
					' Escape symbol
				CASE 92
					token$ = token$ & CHR$(92)
					is_escaped = NOT(is_escaped)
					' Quote symbol
				CASE 34
					token$ = token$ & CHR$(34)
					IF NOT(is_escaped) THEN
						IF NOT(is_string) THEN
							is_string = TRUE
						ELSE
							is_string = FALSE
						ENDIF
					ENDIF
					is_escaped = FALSE
					' Ampersand symbol
				CASE 38
					IF NOT(is_string) AND ISFALSE(g_USE_C) AND ISFALSE(g_USE_H) THEN
						' ITEMIZER1: Get item on the left side
						item1$ = "" : bracket = 0 : in_spac = 0 : in_str = 0 : direct = 0 : isquote = 0
						FOR j = 1 TO LEN(token$)
							SELECT ASC(MID$(token$, LEN(token$)-j+1, 1))
									' Bracket close
								CASE 41, 93
									isquote = 0
									INCR direct
									IF NOT(in_str) THEN
										INCR bracket
									END IF
									' Bracket open
								CASE 40, 91
									isquote = 0
									INCR direct
									IF NOT(in_str) THEN
										DECR bracket
										IF bracket < 0 THEN
											BREAK
										ENDIF
									ENDIF
									' Equation: !=, =
								CASE 61
									isquote = 0
									IF NOT(in_str) THEN BREAK
									' Equation: <>, > skip the '->' construct
								CASE 62
									IF ASC(MID$(token$, LEN(token$)-j, 1)) <> 45 THEN
										isquote = 0
										IF NOT(in_str) THEN BREAK
									ENDIF
									' Comma
								CASE 44
									isquote = 0
									IF NOT(in_str) AND NOT(bracket) THEN BREAK
									' Escape symbol
								CASE 92
									IF isquote THEN
										in_str = 1
									END IF
									isquote = 0
									' Double quote
								CASE 34
									isquote = 1
									INCR direct
									in_str = NOT(in_str)
								CASE 32
									isquote = 0
									IF NOT(in_str) AND NOT(bracket) THEN
										IF direct > 0 THEN
											INCR in_spac
										END IF
									ENDIF
									' Colon
								CASE 58
									IF NOT(bracket) THEN
										isquote = 0
										IF NOT(in_str) THEN BREAK
									ENDIF
							END SELECT
							IF MID$(token$, LEN(token$)-j+1, 1) BETWEEN "a" AND "z" OR MID$(token$, LEN(token$)-j+1, 1) BETWEEN "A" AND "Z" THEN
								isquote = 0
								INCR direct
								IF NOT(in_str) AND NOT(bracket) THEN
									IF in_spac > 0 THEN
										BREAK
									ENDIF
								END IF
							END IF
							item1$ = MID$(token$, LEN(token$)-j+1, 1) & item1$
						NEXT
						' If ITEM is a string element continue
						IF Check_String_Type(item1$) THEN
							token$ = MID$(token$, 1, LEN(token$)-j+1)
							' ITEMIZER2: Get item on the right side
							INCR i
							item2$ = "" : bracket = 0 : in_str = 0 : inescaped = 0 : in_spac = 0 : direct = 0
							FOR j = i TO LEN(current$)
								SELECT ASC(MID$(current$, j, 1))
										' Bracket open
									CASE 40
										INCR direct
										IF NOT(in_str) THEN INCR bracket
										' Bracket close
									CASE 41
										INCR direct
										IF NOT(in_str) THEN
											DECR bracket
											IF bracket < 0 THEN
												BREAK
											ENDIF
										ENDIF
										' Comma, ==, !=, <>
									CASE 44, 60, 61, 33
										IF NOT(in_str) AND NOT(bracket) THEN BREAK
										' Ampersand
									CASE 38
										IF NOT(in_str) AND NOT(bracket) THEN
											in_spac = 0 : direct = 0
										END IF
										' Escape symbol
									CASE 92
										inescaped = NOT(inescaped)
										' Double quote
									CASE 34
										INCR direct
										IF NOT(inescaped) THEN in_str = NOT(in_str)
										inescaped = 0
									CASE 32
										IF NOT(in_str) AND NOT(bracket) THEN
											IF direct > 0 THEN
												INCR in_spac
											END IF
										ENDIF
										' Colon and semicolon
									CASE 58, 59
										IF NOT(in_str) AND NOT(bracket) THEN BREAK
								END SELECT
								IF MID$(current$, j, 1) BETWEEN "a" AND "z" OR MID$(current$, j, 1) BETWEEN "A" AND "Z" THEN
									INCR direct
									IF NOT(in_str) AND NOT(bracket) THEN
										IF in_spac > 0 THEN
											BREAK
										ENDIF
									END IF
								END IF
								IF MID$(current$, j, 1) = "$" THEN
									IF NOT(in_str) OR MATCH(current$, "IMPORT * FROM * TYPE *") THEN
										item2$ = item2$ & g_STRINGSIGN$
									ELSE
										item2$ = item2$ & "$"
									ENDIF
								ELIF MID$(current$, j, 1) = "&" THEN
									IF NOT(in_str) AND NOT(bracket) THEN
										item2$ = item2$ & ","
									ELSE
										item2$ = item2$ & "&"
									END IF
								ELSE
									item2$ = item2$ & MID$(current$, j, 1)
								END IF
							NEXT
							i = j-1
							' Make sure concatenation of literals is done by C - delete comma
							exp$ = item1$ & "," & item2$
							str$ = ""
							' Start miniparser
							WHILE LEN(exp$)
								elem$ = Mini_Parser$(exp$)
								str$ = IIF$(LEN(str$), str$ & "," & elem$, elem$)
								exp$ = MID$(exp$, LEN(elem$)+2)
							WEND
							' Construct concatenation
							token$ = token$ & " CONCAT" & g_STRINGSIGN$ & "(" & str$ & ") "
						ELSE
							token$ = token$ & CHR$(38)
						END IF
					ELSE
						token$ = token$ & CHR$(38)
					END IF
					is_escaped = FALSE
				DEFAULT
					token$ = token$ & MID$(current$, i, 1)
					is_escaped = FALSE
			END SELECT
		NEXT

		IF token$ = result$ THEN BREAK
		result$ = token$
		current$ = token$
	WEND

	' Determine amount of string funcs: substitute string macros
	FOR str$ IN OBTAIN$(g_MACRO_STRINGS$)
		result$ = REPLACE$(result$, str$, g_MACRO_STRINGS$(str$))
	NEXT
	' Determine amount of string funcs: count
	sftot = TALLY(result$, g_STRINGSIGN$ & "(")
	IF sftot > g_STRING_FUNC THEN g_STRING_FUNC = sftot

	' Start parsing
	Parse_Line(CHOP$(token$))

END SUB

'----------------------------------------------------------------------------------------------

FUNCTION Parse_Equation$(STRING current$)

	LOCAL i, is_string, is_escaped, is_equation, opctr, check, is_pointer, flag
	LOCAL chunk$, token$, term$, eq$, total$, element$, last$, v1$, v2$
	LOCAL logop$[32]

	' Initialize parser
	is_string = FALSE
	is_escaped = FALSE
	opctr = 1

	' First split into separate chunks OR/AND
	FOR i = 1 TO LEN(current$)
		IF MID$(current$, i, 9) = " " & g_RANGEOP$ THEN
			IF ISFALSE(is_string) THEN
				flag = 1
			ENDIF
		ELIF MID$(current$, i, 5) = " AND " THEN
			IF NOT(flag) THEN
				IF ISFALSE(is_string) THEN
					chunk$ = chunk$ & CHR$(10)
					logop$[opctr] = " AND "
					INCR opctr : INCR i, 4
				ELSE
					chunk$ = chunk$ & " "
				END IF
			ELSE
				flag = 0
				chunk$ = chunk$ & " "
			ENDIF
		ELIF MID$(current$, i, 4) = " OR " THEN
			IF ISFALSE(is_string) THEN
				chunk$ = chunk$ & CHR$(10)
				logop$[opctr] = " OR "
				INCR opctr : INCR i, 3
			ELSE
				chunk$ = chunk$ & " "
			END IF
		ELIF MID$(current$, i, 1) = CHR$(92) THEN
			chunk$ = chunk$ & CHR$(92)
			is_escaped = NOT(is_escaped)
		ELIF MID$(current$, i, 1) = CHR$(34) THEN
			chunk$ = chunk$ & CHR$(34)
			IF ISFALSE(is_escaped) THEN is_string = NOT(is_string)
			is_escaped = FALSE
		ELSE
			chunk$ = chunk$ & MID$(current$, i, 1)
			is_escaped = FALSE
		END IF
	NEXT
	logop$[opctr] = ""
	opctr = 1

	' Start parsing
	FOR element$ IN chunk$ STEP CHR$(10)

		' Initialize for this chunk
		eq$ = ""
		token$ = ""
		is_equation = 0
		is_string = 0
		is_escaped = 0
		is_pointer = 0

		' Check if this is a string
		check = Check_String_Type(element$)
		IF check THEN
			WHILE REGEX(element$, "^\\(.*\\)$")
				element$ = EXTRACT$(element$, "^\\(|\\)$", TRUE)
			WEND
		ENDIF

		' See if there are equal signs
		FOR i = 1 TO LEN(element$)

			IF LEN(MID$(element$, i)) > 8 AND MID$(element$, i, 8) = g_RANGEOP$ THEN
				term$ = TOKEN$(element$, 2, g_RANGEOP$)
				v1$ = Mini_Parser$(term$, "AND")
				term$ = MID$(term$, LEN(v1$)+1)
				IF REGEX(term$, "AND.*") THEN
					v2$ = MID$(term$, 4)
				ELSE
					v2$ = MID$(term$, 2)
				ENDIF
				IF check THEN
					IF REGEX(v2$, "EXCL$") THEN
						token$ = "(__b2c__STRCMP(" & token$ & ", __b2c__min_str(" & v1$ & "," & LEFT$(v2$, LEN(v2$)-4) & ")) > 0 && __b2c__STRCMP(" & token$ & ", __b2c__max_str(" & v1$ & "," & LEFT$(v2$, LEN(v2$)-4) & ")) < 0 ? 1 : 0)"
					ELSE
						token$ = "(__b2c__STRCMP(" & token$ & ", __b2c__min_str(" & v1$ & "," & v2$ & ")) >= 0 && __b2c__STRCMP(" & token$ & ", __b2c__max_str(" & v1$ & "," & v2$ & ")) <= 0 ? 1 : 0)"
					END IF
					check = 0
				ELSE
					IF REGEX(v2$, "EXCL$") THEN
						token$ = "(" & token$ & " > fmin(" & v1$ & "," & LEFT$(v2$, LEN(v2$)-4) & ") && " & token$ & " < fmax(" & v1$ & "," & LEFT$(v2$, LEN(v2$)-4) & ") ? 1 : 0)"
					ELSE
						token$ = "(" & token$ & " >= fmin(" & v1$ & "," & v2$ & ") && " & token$ & " <= fmax(" & v1$ & "," & v2$ & ") ? 1 : 0)"
					END IF
				ENDIF
				BREAK
			ENDIF

			SELECT MID$(element$, i, 2)
				CASE "=="
					IF ISFALSE(is_string) THEN
						element$ = LEFT$(element$, i-1) & "= " & MID$(element$, i+2)
					END IF
				CASE "<>"
					IF ISFALSE(is_string) THEN
						element$ = LEFT$(element$, i-1) & "!=" & MID$(element$, i+2)
					END IF
			END SELECT

			SELECT ASC(MID$(element$, i, 1))
					' Equation symbol
				CASE 61
					IF ISFALSE(is_string) THEN
						IF check OR Get_Var$(token$, g_FUNCNAME$) = "char*" THEN
							IF LEN(eq$) THEN
								eq$ = eq$ & "="
							ELSE
								term$ = token$
								token$ = ""
								check = TRUE
								eq$ = "=="
							ENDIF
						ELIF NOT(is_equation) THEN
							token$ = "(" & token$ & ")=="
						ELSE
							token$ = token$ & "="
							is_equation = 0
						END IF
					ELSE
						token$ = token$ & "="
					END IF
					' Negation
				CASE 33
					IF ISFALSE(is_string) THEN
						IF check OR Get_Var$(token$, g_FUNCNAME$) = "char*" THEN
							term$ = token$
							token$ = ""
							check = TRUE
							eq$ = "!"
						ELIF NOT(is_equation) THEN
							token$ = "(" & token$ & ")!="
							INCR i
						ELSE
							token$ = token$ & "!"
							is_equation = 0
						END IF
					ELSE
						token$ = token$ & "!"
					END IF
					' Comparison symbols
				CASE 60
					IF ISFALSE(is_string) THEN
						IF check OR Get_Var$(token$, g_FUNCNAME$) = "char*" THEN
							term$ = token$
							token$ = ""
							check = TRUE
							eq$ = "<"
						ELSE
							IF is_equation THEN
								is_equation = 0
							ELSE
								is_equation = 1
							ENDIF
							token$ = token$ & "<"
						ENDIF
					ELSE
						token$ = token$ & "<"
					ENDIF
				CASE 62
					IF NOT(is_string) AND NOT(is_pointer) THEN
						IF check OR Get_Var$(token$, g_FUNCNAME$) = "char*" THEN
							term$ = token$
							token$ = ""
							check = TRUE
							eq$ = ">"
						ELSE
							IF is_equation THEN
								is_equation = 0
							ELSE
								is_equation = 1
							ENDIF
							token$ = token$ & ">"
						ENDIF
					ELSE
						token$ = token$ & ">"
						is_pointer = 0
					ENDIF
					' Minus symbol in pointer
				CASE 45
					token$ = token$ & CHR$(45)
					IF NOT(is_string) AND NOT(is_pointer) THEN
						is_pointer = 1
					ENDIF
					' Escape symbol
				CASE 92
					token$ = token$ & CHR$(92)
					is_escaped = NOT(is_escaped)
					' Quote symbol
				CASE 34
					token$ = token$ & CHR$(34)
					IF ISFALSE(is_escaped) THEN is_string = NOT(is_string)
					is_escaped = FALSE
				DEFAULT
					' Handle normal char after '<' or '>' symbol
					IF is_equation THEN
						is_equation = 0
						last$ = RIGHT$(token$, 1)
						token$ = "(" & LEFT$(token$, LEN(token$)-1) & ")" & last$
					ENDIF
					token$ = token$ & MID$(element$, i, 1)
					is_escaped = FALSE
					is_pointer = FALSE
			END SELECT
		NEXT

		' Construct string equation
		IF check THEN token$ = "__b2c__STRCMP(" & term$ & "," & token$ & ") " & eq$ & " 0"

		total$ = total$ & token$

		' Restore logical operator
		total$ = total$ & logop$[opctr]
		INCR opctr
	NEXT

	RETURN total$

END FUNCTION

'----------------------------------------------------------------------------------------------

SUB Download_File(STRING name$)

	LOCAL total$, dat$, proxy$, unpw$
	LOCAL length, size, mynet

	CATCH GOTO network_error

	' Get environment variable for proxy
	proxy$ = GETENVIRON$("HTTP_PROXY")
	IF LEN(proxy$) = 0 THEN proxy$ = GETENVIRON$("http_proxy")

	' Parse proxy settings
	IF LEN(proxy$) THEN
		IF LEFT$(proxy$, 7) <> "http://" THEN
			EPRINT "System error: proxy '", proxy$, "' not supported! Redefine to default HTTP proxy or undefine."
			END 1
		ENDIF

		proxy$ = MID$(proxy$, 8)
		IF TALLY(proxy$, "@") THEN
			unpw$ = B64ENC$(TOKEN$(proxy$, 1, "@"))
			proxy$ = TOKEN$(proxy$, 2, "@")
		ENDIF

		' Setup TCP connection on defined port
		OPEN proxy$ FOR NETWORK AS mynet

		SEND "CONNECT " & TOKEN$(name$, 1, "/") & ":80 HTTP/1.1" & "\r\n" TO mynet
		IF LEN(unpw$) THEN SEND "Proxy-Authorization: Basic " & B64ENC$(unpw$) & "\r\n" TO mynet
		SEND "\r\n" TO mynet

		' Return should be OK
		RECEIVE dat$ FROM mynet
		IF NOT(TALLY(dat$, " 200 ")) THEN
			EPRINT "System error: proxy '", proxy$, "' returns error: " & dat$
			END 1
		ENDIF
	ELSE
		' Open TCP connection on port 80
		OPEN TOKEN$(name$, 1, "/") & ":80" FOR NETWORK AS mynet
	ENDIF

	PRINT "Fetching file...";

	SEND "HEAD /" & MID$(name$, INSTR(name$, "/")+1) & " HTTP/1.1\r\nHost: " & TOKEN$(name$, 1, "/") & "\r\n\r\n" TO mynet
	RECEIVE dat$ FROM mynet

	' Get the filesize from the HTTP header
	IF NOT(INSTR(dat$, "Content-Length:")) THEN
		EPRINT "System error: file not found! Check URL and try again."
		END 1
	END IF

	dat$ = MID$(dat$, INSTR(dat$, "Content-Length:")+15)
	length = VAL(LEFT$(dat$, INSTR(dat$, NL$)))

	' As long as there is data, get it
	SEND "GET /" & MID$(name$, INSTR(name$, "/")+1) & " HTTP/1.1\r\nHost: " & TOKEN$(name$, 1, "/") & "\r\n\r\n" TO mynet
	WHILE WAIT(mynet, 2000)
		RECEIVE dat$ FROM mynet CHUNK 128 SIZE size
		IF size = 0 THEN BREAK
		EPRINT ".";
		total$ = total$ & dat$
	WEND
	CLOSE NETWORK mynet

	' Rip off HTTP headers
	total$ = MID$(total$, INSTR(total$, "\r\n\r\n")+4)

	' Check amount of data
	IF LEN(total$) != length THEN
		EPRINT "System error: file ", name$, " could not be downloaded probably due to a timeout. Try again later."
		END 1
	END IF

	' Write to file
	SAVE total$ TO MID$(name$, INSTRREV(name$, "/")+1)

	PRINT "done."
	EXIT SUB

	LABEL network_error
		CLOSE NETWORK mynet
		EPRINT "System error: the site http://", LEFT$(name$, INSTR(name$, "/")-1), " is not reachable! Try again later."
		END 1

END SUB

'----------------------------------------------------------------------------

SUB Editor_Print_Line(text$, linenr, inverse)


	LOCAL x, in_string, in_line_comment, in_escaped, pos, len, display_columns
	LOCAL term$, c1$, c2$
	LOCAL in_block_comment = 0 TYPE static int

	COLOR RESET
	IF inverse THEN COLOR INVERSE
	IF Color_Intense THEN COLOR INTENSE

	IF Line_Number_Active THEN
		display_columns = COLUMNS-LEN(STR$(linenr))-1
		PRINT STR$(linenr), " ";
	ELSE
		display_columns = COLUMNS
	ENDIF

	text$ = LEFT$(text$, display_columns)
	len = LEN(text$)

	FOR x = 0 TO len-1

		c1$ = MID$(text$, x+1, 1)
		c2$ = MID$(text$, x+1, 2)

		' Got escape sign?
		IF c1$ = "\\" AND NOT(in_line_comment) AND NOT(in_block_comment) THEN
			IF in_escaped THEN
				in_escaped = 0
			ELSE
				in_escaped = 1
			ENDIF
			' String
		ELIF c1$ = "\"" AND NOT(in_escaped) AND NOT(in_line_comment) AND NOT(in_block_comment) THEN
			in_string = 1 - in_string
			' Block comment start
		ELIF c2$ = "/*" AND NOT(in_string) AND NOT(in_line_comment) THEN
			in_block_comment = TRUE
			in_escaped = FALSE
			' Line comment start
		ELIF c1$ = "'" OR MID$(text$, x+1, 4) = "REM " THEN
			IF NOT(in_string) AND NOT(in_block_comment) THEN
				in_line_comment = TRUE
				in_escaped = FALSE
			ENDIF
			' Line comment end
		ELIF c1$ = NL$ AND NOT(in_string) AND NOT(in_block_comment) THEN
			in_line_comment = FALSE
			in_escaped = FALSE
		ELSE
			in_escaped = FALSE
		ENDIF

		' Highlight string
		IF in_string THEN
			COLOR FG TO Quot_Col
			PRINT MID$(text$, x+1, 1);
			' Highlight block comments
		ELIF in_block_comment THEN
			COLOR FG TO Comm_Col
			TYPE SET ITALIC
			IF MID$(text$, x+1, 2) = "*/" THEN
				PRINT MID$(text$, x+1, 2);
				in_block_comment = FALSE
				INCR x
				TYPE UNSET ITALIC
			ELSE
				PRINT MID$(text$, x+1, 1);
			ENDIF
		ELIF in_line_comment THEN
			COLOR FG TO Comm_Col
			TYPE SET ITALIC
			PRINT MID$(text$, x+1, 1);
		ELSE
			pos = REGEX(MID$(text$, x+1), "[[:space:]]|[=,?;:+-/\\(\\)\\*]|\\[|\\]")-1
			IF pos < 0 THEN pos = len-x

			term$ = "|" & MID$(text$, x+1, pos) & "|"

			IF TALLY(Stat$, term$) THEN
				COLOR FG TO Stat_Col
			ELIF TALLY(EXTRACT$(Func$, "\\"), term$) THEN
				COLOR FG TO Func_Col
			ELIF TALLY(EXTRACT$(Var$, "\\"), term$) THEN
				COLOR FG TO Var_Col
			ELIF TALLY(Type$, term$) THEN
				COLOR FG TO Type_Col
			ELIF MID$(text$, x+1, 1) BETWEEN CHR$(48) AND CHR$(57) THEN
				COLOR FG TO Num_Col
			ELIF MID$(text$, x+1, 1) = CHR$(34) THEN
				COLOR FG TO Quot_Col
			ELIF MID$(text$, x+1, 1) = CHR$(38) THEN
				COLOR FG TO Func_Col
			ELSE
				COLOR FG TO WHITE
			ENDIF
			PRINT MID$(text$, x+1, pos);

			COLOR RESET
			IF inverse THEN COLOR INVERSE
			IF Color_Intense THEN COLOR INTENSE

			PRINT MID$(text$, x+1+pos, 1);

			INCR x, pos
		ENDIF
	NEXT
	IF len < display_columns THEN PRINT EL$;

END SUB

'----------------------------------------------------------------------------

SUB Editor_Print_Text(txt$, line)

	LOCAL y, total_lines

	total_lines = AMOUNT(txt$, NL$)
	IF total_lines = 0 THEN total_lines = 1

	CURSOR OFF
	FOR y = 1 TO ROWS
		GOTOXY 1, y
		IF line <= total_lines THEN
			Editor_Print_Line(TOKEN$(txt$, line, NL$), line, FALSE)
		ELSE
			PRINT CL$;
		ENDIF
		INCR line
	NEXT
	CURSOR ON

ENDSUB

'----------------------------------------------------------------------------

SUB Editor_Restore_Normal

	SIGNAL SIG_DFL, SIGINT
	SCREEN RESTORE
	GOTOXY g_CURSOR_X, g_CURSOR_Y-1
	COLOR RESET
	STOP SIGINT

ENDSUB

'----------------------------------------------------------------------------

SUB Editor_Handle_Input(file$, text$)

	LOCAL xpos = 1, ypos = 1, start = 1, verticalpos = 1, display_columns
	LOCAL key, special, cursor, inskey, delkey, page, total, line, next, x, myposition, nextposition, ins_flag, label_active, wrap_active
	LOCAL line$, prog$, ch$, answer$, option$, man$, str$, result$, ins_line$, word$, arg$

	' Avoid errors in parsing delimited strings when element consists of strings only
	OPTION DQ 1
	OPTION COLLAPSE FALSE

	' Restore ANSI screen when <CTRL>+C is pressed
	SIGNAL Editor_Restore_Normal, SIGINT

	' Store X and Y position of cursor
	g_CURSOR_X = GETX
	g_CURSOR_Y = GETY

	' Save the current screen
	SCREEN SAVE
	Editor_Print_Text(text$, 1)

	WHILE TRUE
		REPEAT
			' Position cursor
			IF Line_Number_Active THEN
				display_columns = COLUMNS-LEN(STR$(start+ypos-1))-1
				GOTOXY xpos+LEN(STR$(start+ypos-1))+1, ypos
			ELSE
				display_columns = COLUMNS
				GOTOXY xpos, ypos
			ENDIF

			' Scan for key and delay at the same time
			key = WAIT(STDIN_FILENO, 100)

			SELECT key
					' No key pressed? Skip
				CASE 0
					CONTINUE

					' Special sequence like <cursor up>, <down>, <alt>+<e> etc
				CASE 27
					special = WAIT(STDIN_FILENO, 100)

					SELECT special
							' One of the special keys
						CASE 91
							cursor = WAIT(STDIN_FILENO, 100)
							SELECT cursor
								CASE 66
									INCR ypos
									IF verticalpos > 1 THEN
										verticalpos = 1
										PRINT CL$;
										GOTOXY 1, ypos-1
										Editor_Print_Line(TOKEN$(text$, start+ypos-2, NL$), start+ypos-2, FALSE)
									ENDIF
								CASE 65
									DECR ypos
									IF verticalpos > 1 THEN
										verticalpos = 1
										PRINT CL$;
										GOTOXY 1, ypos+1
										Editor_Print_Line(TOKEN$(text$, start+ypos, NL$), start+ypos, FALSE)
									ENDIF
								CASE 67
									INCR xpos
								CASE 68
									DECR xpos
								CASE 50
									inskey = WAIT(STDIN_FILENO, 100)
									IF inskey = 126 THEN
										IF ypos < ROWS THEN
											IF ins_flag THEN
												text$ = APPEND$(text$, start+ypos-1, ins_line$, NL$)
												Editor_Print_Text(text$, start)
											ELSE
												ins_line$ = TOKEN$(text$, start+ypos-1, NL$)
											ENDIF
											ins_flag = 1-ins_flag
										ENDIF
									ENDIF
								CASE 51
									delkey = WAIT(STDIN_FILENO, 100)
									IF delkey = 126 THEN
										IF LEN(MID$( TOKEN$(text$, start+ypos-1, NL$), xpos)) <= 1 THEN
											line$ = TOKEN$(text$, start+ypos, NL$)
											text$ = CHANGE$(text$, start+ypos-1, TOKEN$(text$, start+ypos-1, NL$) & line$, NL$)
											text$ = DEL$(text$, start+ypos, NL$)
											Editor_Print_Text(text$, start)
										ELIF xpos < display_columns THEN
											line$ = TOKEN$(text$, start+ypos-1, NL$)
											line$ = LEFT$(line$, xpos-1) & MID$(line$, xpos+1)
											text$ = CHANGE$(text$, start+ypos-1, line$, NL$)
											PRINT CL$;
											GOTOXY 1, ypos
											Editor_Print_Line(line$, start+ypos-1, FALSE)
										ENDIF
									ELIF delkey = 59 THEN
										' Flush buffer
										delkey = WAIT(STDIN_FILENO, 100)
										delkey = WAIT(STDIN_FILENO, 100)
										text$ = DEL$(text$, start+ypos-1, NL$)
										Editor_Print_Text(text$, start)
									ENDIF
									' Home key
								CASE 72
									xpos = 1
									IF verticalpos > 1 THEN
										verticalpos = 1
										GOTOXY 1, ypos
										Editor_Print_Line(MID$(line$, verticalpos), start+ypos-1, FALSE)
									ENDIF
									' End key
								CASE 70
									line$ = TOKEN$(text$, start+ypos-1, NL$)
									xpos = LEN(line$)
									IF xpos > display_columns THEN
										verticalpos = xpos - display_columns + 1
										GOTOXY 1, ypos
										Editor_Print_Line(MID$(line$, verticalpos), start+ypos-1, FALSE)
										xpos = display_columns
									ENDIF
									' Page up key
								CASE 53
									page = WAIT(STDIN_FILENO, 100)
									IF page = 126 THEN
										IF start > ROWS THEN
											DECR start, ROWS
										ELSE
											start = 1
										END IF
										Editor_Print_Text(text$, start)
									END IF
									' Page down key
								CASE 54
									page = WAIT(STDIN_FILENO, 100)
									IF page = 126 THEN
										IF start + 2*ROWS - 1 < AMOUNT(text$, NL$) THEN
											INCR start, ROWS
										ELSE
											start = AMOUNT(text$, NL$)-ROWS+1
											IF start < 1 THEN start = 1
										END IF
										Editor_Print_Text(text$, start)
									END IF
							ENDSELECT

							' Secure range
							IF ypos < 1 THEN
								DECR start
								ypos = 1
								IF start < 1 THEN
									start = 1
								ELSE
									SCROLL DOWN
									GOTOXY 1, 1
									Editor_Print_Line(TOKEN$(text$, start, NL$), start+ypos-1, FALSE)
								ENDIF
							ENDIF

							IF start+ypos-1 > AMOUNT(text$, NL$) THEN
								text$ = APPEND$(text$, 0, "", NL$)
								ypos = AMOUNT(text$, NL$)
								IF ypos > ROWS THEN start = AMOUNT(text$, NL$) - ROWS + 1
								Editor_Print_Text(text$, start)
							ENDIF
							IF ypos > ROWS THEN
								INCR start
								ypos = ROWS
								IF start+ROWS-1 > AMOUNT(text$, NL$) THEN
									start = AMOUNT(text$, NL$) - ROWS + 1
								ELSE
									SCROLL UP
									GOTOXY 1, ROWS
									Editor_Print_Line(TOKEN$(text$, start+ROWS-1, NL$), start+ypos-1, FALSE)
								ENDIF
							ENDIF

							' Take care of a line longer than columns
							IF xpos < 1 THEN
								line$ = TOKEN$(text$, start+ypos-1, NL$)
								IF LEN(line$) > display_columns AND verticalpos > 1 THEN
									DECR verticalpos
									PRINT CL$;
									GOTOXY 1, ypos
									Editor_Print_Line(MID$(line$, verticalpos), start+ypos-1, FALSE)
								ELSE
									verticalpos = 1
								ENDIF
								xpos = 1
							ENDIF

							' Take care of a line longer than columns
							IF xpos > display_columns THEN
								line$ = TOKEN$(text$, start+ypos-1, NL$)
								IF LEN(line$) > display_columns THEN
									INCR verticalpos
									IF verticalpos > LEN(line$)-display_columns+1 THEN verticalpos = LEN(line$)-display_columns+1
									PRINT CL$;
									GOTOXY 1, ypos
									Editor_Print_Line(MID$(line$, verticalpos), start+ypos-1, FALSE)
								ELSE
									verticalpos = 1
								ENDIF
								xpos = display_columns
							ENDIF
					ENDSELECT

					' Backspace
				CASE 127
					IF xpos > 1 THEN
						line$ = TOKEN$(text$, start+ypos-1, NL$)
						line$ = LEFT$(line$, verticalpos-1+xpos-2) & MID$(line$, verticalpos-1+xpos)
						text$ = CHANGE$(text$, start+ypos-1, line$, NL$)
						PRINT CL$;
						GOTOXY 1, ypos
						Editor_Print_Line(MID$(line$, verticalpos), start+ypos-1, FALSE)
						DECR xpos
					ELSE
						line$ = TOKEN$(text$, start+ypos-1, NL$)
						xpos = LEN(TOKEN$(text$, start+ypos-2, NL$))+1
						text$ = CHANGE$(text$, start+ypos-2, TOKEN$(text$, start+ypos-2, NL$) & line$, NL$)
						text$ = DEL$(text$, start+ypos-1, NL$)
						IF AMOUNT(text$, NL$) <= ROWS THEN
							INCR ypos, start-1
							start = 1
						ENDIF
						IF ypos > 1 THEN DECR ypos
						IF xpos > display_columns THEN
							verticalpos = xpos-display_columns+1
							xpos = display_columns
						ENDIF
						Editor_Print_Text(text$, start)
					ENDIF

					' Return key
				CASE 10
					line$ = TOKEN$(text$, start+ypos-1, NL$)
					text$ = CHANGE$(text$, start+ypos-1, LEFT$(line$, verticalpos-1+xpos-1), NL$)
					text$ = APPEND$(text$, start+ypos, MID$(line$, verticalpos-1+xpos), NL$)
					IF ypos = ROWS THEN INCR start
					IF ypos < ROWS THEN INCR ypos
					xpos = 1
					verticalpos = 1
					Editor_Print_Text(text$, start)

					' Other keys
				DEFAULT
					line$ = TOKEN$(text$, start+ypos-1, NL$)
					' Neutralize TAB key
					IF key = 9 THEN
						ch$ = SPC$(4)
					ELSE
						ch$ = CHR$(key)
					ENDIF
					IF xpos > LEN(line$) THEN
						line$ = INSERT$(line$, verticalpos-1+xpos, SPC$(verticalpos-1+xpos-1-LEN(line$)) & ch$)
					ELSE
						line$ = INSERT$(line$, verticalpos-1+xpos, ch$)
					ENDIF
					text$ = CHANGE$(text$, start+ypos-1, line$, NL$)
					GOTOXY 1, ypos
					Editor_Print_Line(MID$(line$, verticalpos), start+ypos-1, FALSE)
					IF xpos < display_columns THEN INCR xpos, IIF(key = 9, 4, 1)
			ENDSELECT
			IF ins_flag THEN
				GOTOXY COLUMNS/2-11, ROWS
				COLOR RESET
				IF Color_Intense THEN COLOR INTENSE
				TYPE SET BLINK
				PRINT CL$, "---=== clipboard active ===---";
				TYPE UNSET BLINK
			ENDIF
		UNTIL special = 0 AND key = 27

		GOTOXY 1, ROWS
		COLOR RESET
		IF Color_Intense THEN COLOR INTENSE
		PRINT CL$, "(N)ew (L)oad (S)ave (F)ind (G)oto (E)xec (H)igh N(r) (I)ndent (D)oc (Q)uit?";
		key = GETKEY

		SELECT LCASE$(CHR$(key))
			CASE "n"
				start = 1
				verticalpos = 1
				xpos = 1
				ypos = 1
				text$ = ""
				file$ = ""
			CASE "l"
				INPUT NL$, "Enter file name... ", file$
				IF NOT(FILEEXISTS(file$)) THEN
					COLOR FG TO RED
					PRINT "WARNING: File does not exist!"
					COLOR RESET
					IF Color_Intense THEN COLOR INTENSE
					PRINT CL$, "Press a key to continue...";
					key = GETKEY
				ELSE
					text$ = REPLACE$(LOAD$(file$), CHR$(9), SPC$(4))
					start = 1
					verticalpos = 1
				ENDIF
			CASE "s"
				IF LEN(file$) THEN
					SAVE REPLACE$(text$, SPC$(4), CHR$(9)) TO file$
					PRINT NL$, "File '" & BASENAME$(file$) & "' saved."
				ELSE
					answer$ = "y"
					INPUT NL$, "Enter file name... ", file$
					IF FILEEXISTS(file$) THEN INPUT "File '", file$, "' exists! Overwrite ([y]/n) ? ", answer$
					IF answer$ = "y" THEN
						SAVE REPLACE$(text$, SPC$(4), CHR$(9)) TO file$
						PRINT "File '" & BASENAME$(file$) & "' saved."
					ELSE
						PRINT "File NOT saved."
					ENDIF
				ENDIF
				PRINT CL$, "Press a key to continue...";
				key = GETKEY
			CASE "f"
				INPUT NL$, "Enter term... ", word$
				PRINT "Searching...";
				total = xpos
				FOR x = 1 TO start+ypos-2
					INCR total, LEN(TOKEN$(text$, x, NL$))+1
				NEXT
				next = INSTR(MID$(text$, total), word$)
				WHILE next > 0
					line = AMOUNT(MID$(text$, 1, total+next), NL$)
					start = IIF(line-ROWS/2 < 1, 1, line-ROWS/2)
					COLOR RESET
					IF Color_Intense THEN COLOR INTENSE
					Editor_Print_Text(text$, start)
					ypos = ROWS/2+1
					GOTOXY 1, IIF(start = 1, line, ypos)
					Editor_Print_Line(TOKEN$(text$, IIF(start = 1, start+line-1, start+ypos-1), NL$), IIF(start = 1, start+line-1, start+ypos-1), TRUE)
					GOTOXY 1, ROWS
					COLOR RESET
					IF Color_Intense THEN COLOR INTENSE
					COLOR INVERSE
					PRINT CL$, "Press [n] for next item, any other key to quit...";
					IF GETKEY <> ASC("n") THEN
						key = 255
						BREAK
					ENDIF
					GOTOXY 1, ROWS
					PRINT CL$, "Searching...";
					INCR total, next
					next = INSTR(MID$(text$, total+1), word$)
				WEND
				IF key <> 255 THEN
					GOTOXY 1, ROWS
					PRINT CL$, "Search ended. Press a key to continue...";
					key = GETKEY
				ENDIF
				COLOR RESET
				IF Color_Intense THEN COLOR INTENSE
			CASE "g"
				INPUT NL$, "Enter line number... ", key
				IF key > AMOUNT(text$, NL$) THEN key = AMOUNT(text$, NL$)
				IF key < ROWS THEN
					start = 1
					ypos = key
				ELIF key > AMOUNT(text$, NL$)-(ROWS/2) THEN
					start = AMOUNT(text$, NL$)-ROWS
					ypos = ROWS - (AMOUNT(text$, NL$)-key)
				ELSE
					start = key-(ROWS/2)
					ypos = key-start+1
				ENDIF
				GOTOXY xpos, ypos
			CASE "e"
				prog$ = DIRNAME$(file$) & "/" & BASENAME$(file$, 1)
				IF FILEEXISTS(prog$) THEN DELETE FILE prog$
				SAVE REPLACE$(text$, SPC$(4), CHR$(9)) TO file$
				PRINT NL$, "Current BaCon command line options: ", option$
				PRINT "Do you want to set new options (y/[n]) ? ";
				IF GETKEY = ASC("y") THEN INPUT NL$, "Enter new options: ", option$
				PRINT NL$, "Executing 'bacon " & option$ & " -d " & DIRNAME$(file$) & " " & file$ & "'..."
				SYSTEM "bacon " & option$ & " -d " & DIRNAME$(file$) & " " & file$
				IF FILEEXISTS(prog$) THEN
					PRINT "Execute ([y]/n) ? ";
					key = GETKEY
					PRINT
					IF key = ASC("y") OR key = 10 THEN
						PRINT "Current program arguments: ", arg$
						PRINT "Do you want to set new arguments (y/[n]) ? ";
						IF GETKEY = ASC("y") THEN INPUT NL$, "Enter new arguments (<enter> means none)... ", arg$
						SCREEN RESTORE
						GOTOXY 1, GETY
						SYSTEM prog$ & " " & arg$
					ENDIF
				ENDIF
				PRINT CL$, "Press a key to continue...";
				key = GETKEY
				SCREEN SAVE
			CASE "h"
				Color_Intense = NOT(Color_Intense)
				IF FILEEXISTS(GETENVIRON$("HOME") & "/.bacon/bacon.cfg" ) THEN
					arg$ = LOAD$(GETENVIRON$("HOME") & "/.bacon/bacon.cfg")
					FOR x = 1 TO AMOUNT(arg$, NL$)
						IF REGEX(TOKEN$(arg$, x, NL$), "^intense") THEN arg$ = DEL$(arg$, x, NL$)
					NEXT
					SAVE APPEND$(arg$, 0, "intense " & STR$(Color_Intense), NL$) TO GETENVIRON$("HOME") & "/.bacon/bacon.cfg"
				ELSE
					SAVE "intense " & STR$(Color_Intense) TO GETENVIRON$("HOME") & "/.bacon/bacon.cfg"
				ENDIF
			CASE "i"
				PRINT NL$, "Applying indentation...";
				result$ = ""
				myposition = nextposition = label_active = wrap_active = 0
				total = AMOUNT(text$, NL$)
				FOR x = 1 TO total
					myposition = nextposition
					line$ = CHOP$(TOKEN$(text$, x, NL$))
					IF LEN(line$) = 0 AND label_active THEN
						label_active = FALSE
						DECR myposition
						nextposition = myposition
					ENDIF
					IF REGEX(line$, "^(CASE|UNTIL)[ \\t]|^(DEFAULT|FI|NEXT|WEND|DONE)|^ELSE$|^ELIF.+THEN$|^END.+") THEN
						IF NOT(REGEX(line$, "^END.+[0-9]+")) THEN DECR myposition
						IF REGEX(line$, "SELECT$") THEN DECR myposition
						IF myposition < 0 THEN myposition = 0
						nextposition = myposition
					ENDIF
					IF REGEX(line$, "^(CASE|ENUM|FOR|FUNCTION|GLOBAL RECORD|LABEL|RECORD|SELECT|SUB|WHILE|DOTIMES|WITH)[ \\t]|^(DEFAULT|REPEAT|USEC|USEH|DO$)|^IF.+THEN$|^ELIF.+THEN$|^ELSE$") THEN
						INCR nextposition
						IF REGEX(line$, "^SELECT") THEN INCR nextposition
						IF LEFT$(line$, 5) = "LABEL" THEN label_active = TRUE
					ENDIF
					IF RIGHT$(line$, 2) = CHR$(32) & CHR$(92) THEN
						IF NOT(wrap_active) THEN INCR nextposition
						wrap_active = TRUE
					ELSE
						IF wrap_active THEN DECR nextposition
						wrap_active = FALSE
					ENDIF
					IF LEN(line$) THEN
						result$ = result$ & SPC$(myposition*4) & line$ & NL$
					ELSE
						result$ = result$ & NL$
					ENDIF
				NEXT
				text$ = result$
				PRINT CL$, "Press a key to continue...";
				key = GETKEY
			CASE "r"
				Line_Number_Active = 1 - Line_Number_Active
				IF FILEEXISTS(GETENVIRON$("HOME") & "/.bacon/bacon.cfg" ) THEN
					arg$ = LOAD$(GETENVIRON$("HOME") & "/.bacon/bacon.cfg")
					FOR x = 1 TO AMOUNT(arg$, NL$)
						IF REGEX(TOKEN$(arg$, x, NL$), "^linenr") THEN arg$ = DEL$(arg$, x, NL$)
					NEXT
					SAVE APPEND$(arg$, 0, "linenr " & STR$(Line_Number_Active), NL$) TO GETENVIRON$("HOME") & "/.bacon/bacon.cfg"
				ELSE
					SAVE "linenr " & STR$(Line_Number_Active) TO GETENVIRON$("HOME") & "/.bacon/bacon.cfg"
				ENDIF
			CASE "d"
				myposition = xpos
				FOR x = 1 TO start+ypos-2
					INCR myposition, LEN(TOKEN$(text$, x, NL$))+1
				NEXT
				WHILE NOT(REGEX(MID$(text$, myposition, 1), "[[:space:]]|[=,?;:+-/\\(\\)\\*]"))
					DECR myposition
					IF myposition = 0 THEN BREAK
				WEND
				INCR myposition
				total = 1
				WHILE NOT(REGEX(MID$(text$, myposition+total, 1), "[[:space:]]|[=,?;:+-/\\(\\)\\*]"))
					INCR total
					IF myposition+total > LEN(text$) THEN BREAK
				WEND
				word$ = MID$(text$, myposition, total)
				CLEAR
				GOTOXY 1, 1
				IF ISTRUE(LEN(EXEC$("which less 2>/dev/null"))) THEN
					SCREEN RESTORE
					SYSTEM "man bacon | less -p '^     " & REPLACE$(word$, "$", "\\$") & "'"
					SCREEN SAVE
				ELSE
					SYSTEM "man bacon | more -d -p +/'^     " & REPLACE$(word$, "$", "\\$") & "'"
				ENDIF
			CASE "q"
				BREAK
			DEFAULT
				IF key <> 27 THEN
					COLOR FG TO RED
					PRINT NL$, "WARNING: invalid option!"
					COLOR RESET
					IF Color_Intense THEN COLOR INTENSE
					INPUT "Press <return> to continue...", key
				ELSE
					GOTOXY 1, ROWS
					PRINT CL$;
					IF AMOUNT(text$, NL$) >= start+ROWS-1 THEN Editor_Print_Line(TOKEN$(text$, start+ROWS-1, NL$), start+ROWS-1, FALSE)
					CONTINUE
				ENDIF
		ENDSELECT

		Editor_Print_Text(text$, start)
	WEND

	' Back to normal screen
	CALL Editor_Restore_Normal

END SUB

'----------------------------------------------------------------------------------------------
'
' Main program
'
'----------------------------------------------------------------------------------------------

' Default BACON settings
LET g_MAX_DIGITS = 32

' This is the size for static buffers like getline, read etc.
LET g_BUFFER_SIZE = 512

' Maximum RETURN buffers
LET g_MAX_RBUFFERS = 64

' Defaults for parameters
g_CCNAME$ = ""
g_TEMPDIR$ = ""
g_INCFILES$ = ""
g_CCFLAGS$ = ""
g_BINEXT$ = ""

g_CCNAME_TMP$ = ""
g_TEMPDIR_TMP$ = ""
g_INCFILES_TMP$ = ""
g_LDFLAGS_TMP$ = ""
g_CCFLAGS_TMP$ = ""

LET g_NO_COMPILE = 0
LET g_TMP_PRESERVE = 0
LET g_QUIET = 0
LET g_SEMANTIC = 0
LET g_NO_QUESTION = 0
LET g_CPP = 0
LET g_XGETTEXT = 0
LET g_SAVE_CONFIG = 0
LET g_DEBUG = 0
LET g_LOWERCASE = 0

LET g_USE_C = 0
LET g_USE_H = 0
LET g_MAX_BACKLOG = 5

g_INCLUDE_FILES$ = ""
g_PRAGMA_INCLUDE$ = ""
g_PRAGMA_REGEX$ = ""
LET g_TRACE = 0
LET g_OPTION_BASE = 0
LET g_OPTION_SOCKET = 5
LET g_OPTION_TLS = 0
LET g_OPTION_EVAL = 0
g_INC_TLS$ = ""
g_LIB_TLS$ = ""
g_WHICH_GUI = 0
LET g_OPTION_BREAK = 1

' Some global declarations
DECLARE g_ALL_MAIN_VARS$ ASSOC STRING
DECLARE g_ALL_FUNC_VARS$ ASSOC STRING
DECLARE g_ALL_DIM_VARS$ ASSOC STRING
DECLARE g_SEMANTIC_MEMFREE$ ASSOC STRING
DECLARE g_SEMANTIC_OPENCLOSE$ ASSOC STRING
DECLARE g_MACRO_STRINGS$ ASSOC STRING
g_CURFILE$ = ""
g_FUNCNAME$ = ""
g_SOURCEFILE$ = ""
g_FUNCTYPE$ = ""
g_PROTOTYPE$ = ""
g_TMP_FILES$ = ""
g_LOCALSTRINGS$ = ""
g_STRINGARRAYS$ = ""
g_STRINGARGS$ = ""
g_DYNAMICARRAYS$ = ""
g_STATICARRAYS$ = ""
g_RECORDCACHE$ = ""
LET g_LOOPCTR = 0
g_ERRORTXT$ = ""
g_COMMENT = FALSE
g_TRACE_PREFIX$ = ""
g_IGNORE_PARSE$ = "TRUE"
g_OPTION_EXPLICIT$ = "FALSE"
g_OPTION_INPUT$ = "\"\\n\""
g_VARTYPE$ = "long"
g_OBJ_FILES$ = ""
g_MAKE_LINE$ = ""
g_MONITOR$ = ""
g_STRING_FUNC = 1
g_DOTIMES = 0
g_LOCAL_SBUFFER$ = ""

' Always create a final label
g_CATCHGOTO$ = "__B2C__PROGRAM__EXIT"
g_CATCH_USED = 0

' Records
g_RECORDNAME$ = ""
g_RECORDVAR$ = ""
g_RECORDARRAY$ = ""
g_WITHVAR$ = ""
g_RECORDEND_BODY$ = ""
g_RECORDEND_HEADER$ = ""

' Socket defaults
g_SOCKTYPE$ = "SOCK_STREAM"
g_NETWORKTYPE$ = "TCP"
g_MULTICAST_TTL = 1
g_SCTP_STREAMS = 1

' Select/Case currently 16 levels deep
DECLARE g_SELECTVAR$[16]
DECLARE g_IN_CASE[16]
g_SELECTVAR_CTR = 0

' Relate currently 256
DECLARE g_RELATE$[256]
g_RELATE_CTR = 0

g_FCTR = 0
g_CCTR = 0

' Cursor positions for ASCII editor
g_CURSOR_X = 0
g_CURSOR_Y = 0

' Timer and dir related
DECLARE starttime, ttime, nolex, RETURN_CODE
DECLARE msec_time$, old_curdir$, mapping$

' Read any configfile values
IF NOT(FILEEXISTS(GETENVIRON$("HOME") & "/.bacon/")) THEN MAKEDIR GETENVIRON$("HOME") & "/.bacon/"

IF FILEEXISTS(GETENVIRON$("HOME") & "/.bacon/bacon.cfg" ) THEN
	OPEN GETENVIRON$("HOME") & "/.bacon/bacon.cfg" FOR READING AS cfgfile
	WHILE NOT(ENDFILE(cfgfile))
		READLN line$ FROM cfgfile
		SELECT TOKEN$(line$, 1)
			CASE "ccname"
				g_CCNAME_TMP$ = TOKEN$(line$, 2)
			CASE "tempdir"
				g_TEMPDIR_TMP$ = TOKEN$(line$, 2)
			CASE "incfiles"
				g_INCFILES_TMP$ = TOKEN$(line$, 2)
			CASE "ldflags"
				g_LDFLAGS_TMP$ = TOKEN$(line$, 2)
			CASE "ccflags"
				g_CCFLAGS_TMP$ = TOKEN$(line$, 2)
			CASE "lowercase"
				g_LOWERCASE_TMP = VAL(TOKEN$(line$, 2))
			CASE "intense"
				Color_Intense = VAL(TOKEN$(line$, 2))
			CASE "linenr"
				Line_Number_Active = VAL(TOKEN$(line$, 2))
		END SELECT
	WEND
	CLOSE FILE cfgfile
ENDIF

REPEAT
	opt = CMDLINE(":c:d:i:l:o:r:e:xnjfpqsvwyz@")
	SELECT opt
			' Compiler option
		CASE 99
			g_CCNAME$ = ARGUMENT$

			' Include option
		CASE 105
			IF LEFT$(ARGUMENT$) = "/" OR LEFT$(ARGUMENT$, 2) = "./" THEN
				g_INCFILES$ = g_INCFILES$ & "#include " & CHR$(34) & ARGUMENT$ & CHR$(34)
			ELIF LEFT$(ARGUMENT$) = "<" THEN
				g_INCFILES$ = g_INCFILES$ & "#include " & ARGUMENT$
			ELSE
				g_INCFILES$ = g_INCFILES$ & "#include " & CHR$(34) & CURDIR$ & "/" & ARGUMENT$ & CHR$(34)
			END IF

			' Library flags
		CASE 108
			IF LEFT$(ARGUMENT$, 1) = "`" OR LEFT$(ARGUMENT$, 1) = "-" THEN
				g_LDFLAGS$ = ARGUMENT$ & " " & g_LDFLAGS$
			ELSE
				g_LDFLAGS$ = "-l" & ARGUMENT$ & " " & g_LDFLAGS$
			ENDIF

			' Compiler flags
		CASE 111
			g_CCFLAGS$ = g_CCFLAGS$ & " " & ARGUMENT$

			' Temporary directory
		CASE 100
			IF NOT(FILEEXISTS(ARGUMENT$)) THEN MAKEDIR ARGUMENT$
			g_TEMPDIR$ = ARGUMENT$

			' Help option
		CASE 104;
		CASE 63;
		CASE 45
			PRINT NL$, "USAGE: bacon [options] program[.bac]"
			PRINT NL$, "OPTIONS:"
			PRINT NL$, " -c <compiler>", TAB$(1), "Compiler to use (default: cc)"
			PRINT " -l <ldflags>", TAB$(1), "Pass libraries to linker"
			PRINT " -o <options>", TAB$(1), "Pass compiler options"
			PRINT " -i <include>", TAB$(1), "Add include file to C code"
			PRINT " -d <tmpdir>", TAB$(1), "Temporary directory (default: .)"
			PRINT " -e <file.bac>", TAB$(1), "Use embedded editor"
			PRINT " -y ", TAB$(2), "Automatically delete temporary files"
			PRINT " -x ", TAB$(2), "Extract gettext strings"
			PRINT " -z ", TAB$(2), "Allow lowercase keywords"
			PRINT " -f ", TAB$(2), "Create Shared Object"
			PRINT " -n ", TAB$(2), "Do not compile, only convert"
			PRINT " -j ", TAB$(2), "Invoke C Preprocessor"
			PRINT " -p ", TAB$(2), "Preserve temporary files"
			PRINT " -q ", TAB$(2), "Show summary after conversion only"
			PRINT " -s ", TAB$(2), "Suppress semantic error warnings"
			PRINT " -w ", TAB$(2), "Save options to BaCon configfile"
			PRINT " -v ", TAB$(2), "Show version"
			PRINT " -h ", TAB$(2), "Show help", NL$
			END

			' Version option
		CASE 118
			PRINT NL$, "BaCon version ", g_VERSION$, " on ", OS$, " - (c) Peter van Eerten - MIT License.", NL$
			END

			' Preserve option
		CASE 112
			g_TMP_PRESERVE = 1

			' Quiet option
		CASE 113
			g_QUIET = 1

			' Suppress semantic errors
		CASE 115
			g_SEMANTIC = 1

			' Gettext option
		CASE 120
			g_XGETTEXT = 1

			' Automatic delete option
		CASE 121
			g_NO_QUESTION = 1

			' No compile option
		CASE 110
			g_NO_COMPILE = 1

			' Goto internal editor
		CASE 101
			g_SOURCEFILE$ = IIF$(RIGHT$(ARGUMENT$, 4) != ".bac", ARGUMENT$ & ".bac", ARGUMENT$)
			IF FILEEXISTS(g_SOURCEFILE$) THEN
				Editor_Handle_Input(g_SOURCEFILE$, REPLACE$(LOAD$(g_SOURCEFILE$), CHR$(9), SPC$(4)))
			ELSE
				Editor_Handle_Input(g_SOURCEFILE$, "")
			ENDIF
			END

			' Invoke C Preprocessor
		CASE 106
			g_CPP = 1

			' Allow lowercase keywords
		CASE 122
			g_LOWERCASE = 1

			' Shared library
		CASE 102
			g_LDFLAGS$ = g_LDFLAGS$ & " -shared -rdynamic"
			g_CCFLAGS$ = g_CCFLAGS$ & " -fPIC"
			g_BINEXT$ = ".so"

			' Write config
		CASE 119
			g_SAVE_CONFIG = 1

			' Debug flag
		CASE 64
			g_DEBUG = 1

	END SELECT
UNTIL opt = -1

' See if configfile must be written
IF g_SAVE_CONFIG = 1 THEN
	OPEN GETENVIRON$("HOME") & "/.bacon/bacon.cfg" FOR WRITING AS cfgfile
	WRITELN "ccname ", g_CCNAME$ TO cfgfile
	WRITELN "tempdir ", g_TEMPDIR$ TO cfgfile
	WRITELN "incfiles ", REPLACE$(g_INCFILES$, "#include", "@") TO cfgfile
	WRITELN "ldflags ", g_LDFLAGS$ TO cfgfile
	WRITELN "ccflags ", g_CCFLAGS$ TO cfgfile
	WRITELN "lowercase ", g_LOWERCASE TO cfgfile
	WRITELN "intense ", Color_Intense TO cfgfile
	WRITELN "linenr ", Line_Number_Active TO cfgfile
	CLOSE FILE cfgfile
	g_CCNAME_TMP$ = g_CCNAME$
	g_TEMPDIR_TMP$ = g_TEMPDIR$
	g_INCFILES_TMP$ = REPLACE$(g_INCFILES$, "#include", "@")
	g_LDFLAGS_TMP$ = g_LDFLAGS$
	g_CCFLAGS_TMP$ = g_CCFLAGS$
	g_LOWERCASE_TMP = g_LOWERCASE
ENDIF

' Use the commandline or configfile settings?
IF NOT(LEN(g_CCNAME$)) THEN
	g_CCNAME$ = g_CCNAME_TMP$
	IF NOT(LEN(g_CCNAME$)) THEN g_CCNAME$ = "cc"
ENDIF
IF NOT(LEN(g_TEMPDIR$)) THEN
	g_TEMPDIR$ = g_TEMPDIR_TMP$
	IF NOT(LEN(g_TEMPDIR$)) THEN g_TEMPDIR$ = "."
ENDIF
IF NOT(LEN(g_INCFILES$)) THEN g_INCFILES$ = REPLACE$(g_INCFILES_TMP$, "@", "#include")
g_LDFLAGS$ = g_LDFLAGS$ & " " & g_LDFLAGS_TMP$
IF NOT(LEN(g_CCFLAGS$)) THEN g_CCFLAGS$ = g_CCFLAGS_TMP$
IF g_LOWERCASE = 0 THEN g_LOWERCASE = g_LOWERCASE_TMP

IF NOT(LEN(ARGUMENT$)) THEN
	IF g_SAVE_CONFIG = 0 THEN EPRINT "System error: no filename? Run with '-h' to see usage."
	END 1
ELSE
	g_SOURCEFILE$ = ARGUMENT$
ENDIF

IF LEFT$(g_SOURCEFILE$, 7) = "http://" THEN
	g_SOURCEFILE$ = MID$(g_SOURCEFILE$, 8)
	Download_File(g_SOURCEFILE$)
	g_SOURCEFILE$ = MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/")+1)
ELIF RIGHT$(g_SOURCEFILE$, 4) != ".bac" THEN
	g_SOURCEFILE$ = CHOP$(g_SOURCEFILE$) & ".bac"
END IF

IF NOT(FILEEXISTS(g_SOURCEFILE$)) THEN
	EPRINT "System error: file '", g_SOURCEFILE$, "' not found!"
	END 1
ENDIF

' Change the working directory
IF INSTR(g_SOURCEFILE$, "/") AND LEFT$(g_SOURCEFILE$, 1) = "/" THEN CHANGEDIR MID$(g_SOURCEFILE$, 1, INSTRREV(g_SOURCEFILE$, "/")-1)

' Now create the global filenames where to write to
g_CFILE$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".c"
g_HFILE$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".h"
g_GENERIC$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".generic.h"
g_FUNCTIONS$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".functions.h"
STRINGARRAYFILE$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".string.h"
FLOATARRAYFILE$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".float.h"
SRCARRAYFILE$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".src.h"
g_BACONLEXER$ = g_TEMPDIR$ & "/" & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".lex"

' Add to total file list
g_TMP_FILES$ = g_TMP_FILES$ & " " & g_CFILE$ & " " & g_HFILE$ & " " & STRINGARRAYFILE$ & " " & FLOATARRAYFILE$

' Check if previous temporary files exist
total$ = WALK$(g_TEMPDIR$, 1, BASENAME$(g_SOURCEFILE$, 1) & "\\..+\\..+", FALSE)

IF g_NO_QUESTION THEN
	FOR tmpfile$ IN total$
		DELETE FILE tmpfile$
	NEXT
ELSE
	IF AMOUNT(total$) THEN
		PRINT "WARNING: ", AMOUNT(total$), " temporary files found!", NL$, DELIM$(SORT$(total$), " ", NL$)
		INPUT "Do you want to delete them ([y]/n)? ", answer$
		IF LEN(answer$) = 0 OR LCASE$(answer$) = "y" THEN
			FOR tmpfile$ IN total$
				DELETE FILE tmpfile$
			NEXT
			PRINT "Temporary files were deleted."
		ELSE
			PRINT "Exiting..."
			END 1
		ENDIF
	ENDIF
ENDIF

' Keep start time
starttime = TIMER

' Create C file
OPEN g_CFILE$ FOR WRITING AS g_CFILE
WRITELN "/* Created with BaCon ", g_VERSION$, " - (c) Peter van Eerten - MIT License */" TO g_CFILE
WRITELN "#include \"", MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1), ".h\"" TO g_CFILE
WRITELN "#include \"", MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1), ".string.h\"" TO g_CFILE
WRITELN "#include \"", MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1), ".float.h\"" TO g_CFILE

' Create H file
OPEN g_HFILE$ FOR WRITING AS g_HFILE
WRITELN "/* Created with BaCon ", g_VERSION$, " - (c) Peter van Eerten - MIT License */" TO g_HFILE
WRITELN "#include " & CHR$(34) & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".generic.h" & CHR$(34) TO g_HFILE
WRITELN "#include " & CHR$(34) & MID$(g_SOURCEFILE$, INSTRREV(g_SOURCEFILE$, "/") + 1) & ".functions.h" & CHR$(34) TO g_HFILE

' Create generic headerfile, functions are converted using macros
OPEN g_GENERIC$ FOR WRITING AS g_GENERIC
WRITELN "/* Created with BaCon ", g_VERSION$, " - (c) Peter van Eerten - MIT License */" TO g_GENERIC

OPEN STRINGARRAYFILE$ FOR WRITING AS STRINGARRAYFILE
WRITELN "char* __b2c__stringarray[] = {" TO STRINGARRAYFILE

OPEN FLOATARRAYFILE$ FOR WRITING AS FLOATARRAYFILE
WRITELN "double __b2c__floatarray[] = {" TO FLOATARRAYFILE

IF INSTR(g_LDFLAGS$, "shared") THEN
	WRITELN "/************************************/" TO g_CFILE
	WRITELN "/* Init function for shared objects */" TO g_CFILE
	WRITELN "/************************************/" TO g_CFILE
	WRITELN "#ifdef __GNUC__" TO g_CFILE
	WRITELN "static int BaCon_init() __attribute__((constructor));" TO g_CFILE
	WRITELN "#endif" TO g_CFILE
	WRITELN "int BaCon_init(void){int argc=0; char *argv[2] = { NULL };" TO g_CFILE
ELSE
	WRITELN "/****************************/" TO g_CFILE
	WRITELN "/* Main program starts here */" TO g_CFILE
	WRITELN "/****************************/" TO g_CFILE
	WRITELN "int main(int argc, char **argv){" TO g_CFILE
ENDIF

' Set buffering to line oriented
WRITELN "setvbuf(stdout, NULL, _IOLBF, 0);" TO g_CFILE

' Check version
WRITELN "if(argc>0) { __b2c__me_var", g_STRINGSIGN$, " = strdup(argv[0]); }" TO g_CFILE

' See if we have the detector
WRITELN "if(argc==2 && !strcmp(argv[1], \"-bacon\")){fprintf(stderr, \"Converted by %s.\\n\", COMPILED_BY_WHICH_BACON", g_STRINGSIGN$, "); exit(EXIT_SUCCESS);}" TO g_CFILE

' Put arguments into reserved variable ARGUMENT
WRITELN "/* Setup the reserved variable 'ARGUMENT' */" TO g_CFILE
WRITELN "__b2c__argument(&ARGUMENT", g_STRINGSIGN$, ", argc, argv);" TO g_CFILE
WRITELN "/* By default seed random generator */" TO g_CFILE
WRITELN "srandom((unsigned int)time(NULL));" TO g_CFILE
WRITELN "/* Determine current moment and keep it for timer function */" TO g_CFILE
WRITELN "__b2c__timer(1);" TO g_CFILE
WRITELN "/* Setup error signal handling */" TO g_CFILE
WRITELN "signal(SIGILL, __b2c__catch_signal);" TO g_CFILE
WRITELN "signal(SIGABRT, __b2c__catch_signal);" TO g_CFILE
WRITELN "signal(SIGFPE, __b2c__catch_signal);" TO g_CFILE
WRITELN "signal(SIGSEGV, __b2c__catch_signal);" TO g_CFILE
WRITELN "/* Rest of the program */" TO g_CFILE

' There are no imported symbols yet
LET g_IMPORTED$ = ""

' Define statements
CONST Stat$ = "|ALARM|ALIAS|APPEND|APPENDING|ARRAY|AS|ASSOC|BACK|BAPPEND|BASE|BG|BLACK|BLINK|BLUE|BOLD|BREAK|BROADCAST|BSAVE|" \
	"BY|CALL|CASE|CATCH|CERTIFICATE|CHANGEDIR|CHUNK|CLASS|CLEAR|CLOSE|CMODE|COLLAPSE|COLOR|COMPARE|COMPILER|COLLECT|" \
	"CONST|CONTINUE|COPY|CURRENT|CURSOR|CYAN|DATA|DECLARE|DECR|DEF|DEFAULT|DELETE|DELIM|DEVICE|DIRECTORY|DO|" \
	"DONE|DOTIMES|DOWN|DOWNTO|DQ|ELIF|ELSE|END|ENDCLASS|ENDENUM|ENDFORK|ENDFUNCTION|ENDIF|ENDRECORD|ENDSELECT|ENDSUB|" \
	"ENDUSEC|ENDUSEH|ENDWITH|ENDFUNC|ENUM|EPRINT|EQ|ESC|EXIT|EXPLICIT|FG|FI|FILE|FN|FOR|FORMAT|FORWARD|FRAMEWORK|FREE|" \
	"FROM|FUNC|FUNCTION|GE|GETBYTE|GETFILE|GETLINE|GLOBAL|GOSUB|GOTO|GOTOXY|GREEN|GT|GUI|IF|IMODE|IMPORT|IN|INCLUDE|" \
	"INCR|INPUT|INTENSE|INTERNATIONAL|INVERSE|IS|ISNOT|ITALIC|JOIN|LABEL|LDFLAGS|LE|LET|LIBRARY|LMODE|LOCAL|LOOKUP|" \
	"LT|MAGENTA|MAKEDIR|MAP|MEMREWIND|MEMSTREAM|MEMTYPE|MONITOR|MULTICAST|NE|NETWORK|NEXT|NORMAL|OFF|OFFSET|NODE|" \
	"OMODE|ON|OPEN|OPTION|OPTIONS|OTHER|PARSE|POKE|PRAGMA|PRINT|PROPER|PROTO|PULL|PUSH|PUTBYTE|PUTLINE|QUOTED|" \
	"RE|READ|READING|READLN|READWRITE|RECEIVE|RECORD|RECURSIVE|RED|REDIM|RELATE|REM|RENAME|REPEAT|RESET|RESIZE|TREE|" \
	"RESTORE|RESUME|RETURN|REWIND|RUN|SAVE|SCREEN|SCROLL|SCTP|SEED|SEEK|SELECT|SEND|SERVER|SET|SETENVIRON|SETSERIAL|SIGNAL|" \
	"SIZE|SLEEP|SOCKET|SORT|SPEED|SPLIT|START|STARTPOINT|STATIC|STEP|STOP|STRIKE|SUB|SWAP|SYSTEM|TCP|TEXTDOMAIN|THEN|" \
	"TLS|TO|TRACE|TRAP|TYPE|UDP|UNDERLINE|UNSET|UNTIL|UP|USEC|USEH|UTF8|VAR|VARTYPE|WEND|WHENCE|WHILE|WHITE|WITH|WRITELN|WRITING|" \
	"YELLOW|"
CONST Stat_Col = 2

' Define functions
CONST Func$ = "|ABS|ACCEPT|ACOS|ADDRESS|ALIGN\\$|AMOUNT|AND|APPEND\\$|ASC|ASIN|ATN|ATN2|B64DEC\\$|B64ENC\\$|BASENAME\\$|COIL\\$|" \
	"BETWEEN|BIN\\$|BIT|BLOAD|BYTELEN|CEIL|CA\\$|CN\\$|CHANGE\\$|COLLAPSE\\$|CHOP\\$|CHR\\$|CIPHER\\$|CMDLINE|COLUMNS|CONCAT\\$|COS|COUNT|" \
	"CURDIR\\$|CUT\\$|DAY|DEC|DEG|DEL\\$|DELIM\\$|DIRNAME\\$|ENDFILE|EQUAL|ERR\\$|ERROR|ESCAPE\\$|EVAL|EVEN|EXCHANGE\\$|EXCL|EXEC\\$|" \
	"EXP|EXPLODE\\$|EXTRACT\\$|FILEEXISTS|FILELEN|FILETIME|FILETYPE|FILL\\$|FIRST\\$|FLATTEN\\$|FLOOR|FORK|FP|GUIFN|GUIDEFINE|GUIGET|GUISET|" \
	"GUIEVENT\\$|GUIWIDGET|GETENVIRON\\$|GETKEY|GETPEER\\$|GETX|GETY|HASDELIM|HASH|HEAD\\$|HEX\\$|HOST\\$|HOSTNAME\\$|HOUR|IIF|IIF\\$|" \
	"INBETWEEN\\$|INDEX|INSERT\\$|INSTR|INSTRREV|INT|INTL\\$|ISASCII|ISFALSE|ISKEY|ISTOKEN|ISTRUE|ISUTF8|LAST\\$|LCASE\\$|LEFT\\$|LEN|LOAD\\$|" \
	"LOG|LOOP|LOOP\\$|MATCH|MAX|MAX\\$|MAXNUM|ME\\$|MEMCHECK|MEMORY|MEMTELL|MERGE\\$|MID\\$|MIN|MIN\\$|MINUTE|MOD|MONTH|MONTH\\$|MYPID|" \
	"NNTL\\$|NOT|NOW|NRKEYS|OBTAIN\\$|ODD|OR|OS\\$|OUTBETWEEN\\$|PEEK|POW|PROPER\\$|RAD|RANDOM|REALPATH\\$|REAP|RIP\\$|" \
	"REGEX|REPLACE\\$|REV\\$|REVERSE\\$|RIGHT\\$|RND|ROL|ROR|ROTATE\\$|ROUND|ROWS|RUN\\$|SEARCH|SECOND|SGN|SIN|SIZEOF|FIND|" \
	"SORT\\$|SPC\\$|SQR|STR\\$|SUM|SUMF|TAB\\$|TAIL\\$|TALLY|TAN|TELL|TIMER|TIMEVALUE|TOASCII\\$|TOKEN\\$|TYPEOF\\$|UCASE\\$|" \
	"UBOUND|UCS|ULEN|UNFLATTEN\\$|UNESCAPE\\$|UNIQ\\$|UTF8\\$|VAL|VERIFY|WAIT|WALK\\$|WEEK|WEEKDAY\\$|YEAR|"
CONST Func_Col = 6

' Variables
CONST Var$ = "|FALSE|TRUE|PI|MAXRANDOM|RETVAL|REGLEN|LINENO|SP|NL\\$|CR\\$|EL\\$|CL\\$|DLE\\$|VERSION\\$|ARGUMENT\\$|SOURCE\\$|NULL|" \
	"NUMBER|STRING|FLOATING|"
CONST Var_Col = 3

' Types
CONST Type$ = "|int|double|float|long|char|short|void|signed|unsigned|static|volatile|struct|extern|public|private|virtual|"
CONST Type_Col = 3

' Numbers
CONST Num$ = "|0|1|2|3|4|5|6|7|8|9|"
CONST Num_Col = 1

' Comments
CONST Comm$ = "|REM|'|/\\*|"
CONST Comm_Col = 4

CONST Mlc$ = "\\*/"

' Quoted text
CONST Quot_Col = 5

' Allow lowercase statements and functions
IF ISTRUE(g_LOWERCASE) THEN
	FOR kwd$ IN Stat$ STEP "|"
		mapping$ = mapping$ & " -D" & LCASE$(kwd$) & "=" & kwd$
	NEXT
	FOR kwd$ IN EXTRACT$(Func$, "\\") STEP "|"
		mapping$ = mapping$ & " -D" & LCASE$(kwd$) & "=" & kwd$
	NEXT
	FOR kwd$ IN EXTRACT$(Var$, "\\") STEP "|"
		mapping$ = mapping$ & " -D" & LCASE$(kwd$) & "=" & kwd$
	NEXT
	LET g_CPP = 1
ELSE
	mapping$ = ""
ENDIF

' Check if the C Preprocessor needs to run
IF ISTRUE(g_CPP) THEN
	IF ISTRUE(LEN(EXEC$("which cpp 2>/dev/null"))) THEN
		PRINT "Preprocessing '", g_SOURCEFILE$, "'... ";
		' Change next line marker to overcome C preprocessor interpretation
		OPEN g_SOURCEFILE$ & ".tmp" FOR WRITING AS src_tmp
		OPEN g_SOURCEFILE$ FOR READING AS src_in
		WHILE NOT(ENDFILE(src_in))
			READLN line$ FROM src_in
			IF LEFT$(line$, 1) = "#" THEN
				WRITELN line$ TO src_tmp
			ELSE
				WRITELN "@" & line$ & "@" TO src_tmp
			ENDIF
		WEND
		CLOSE FILE src_in, src_tmp
		SYSTEM "cpp -w -P " & mapping$ & " " & g_SOURCEFILE$ & ".tmp " & g_SOURCEFILE$ & ".cpp"
		' Restore next line marker
		OPEN g_SOURCEFILE$ & ".cpp" FOR READING AS src_cpp
		OPEN g_SOURCEFILE$ & ".bac2" FOR WRITING AS src_out
		WHILE NOT(ENDFILE(src_cpp))
			READLN line$ FROM src_cpp
			WRITELN MID$(line$, 2, LEN(line$)-2) TO src_out
		WEND
		CLOSE FILE src_out, src_cpp
		FEED$ = g_SOURCEFILE$ & ".bac2"
		g_TMP_FILES$ = g_TMP_FILES$ & " " & g_SOURCEFILE$ & ".cpp" & " " & g_SOURCEFILE$ & ".tmp" & " " & g_SOURCEFILE$ & ".bac2"
		PRINT "done."
	ELSE
		IF ISTRUE(g_LOWERCASE) THEN
			EPRINT "System error: the C Preprocessor 'cpp' not found, cannot parse lowercase! Exiting..."
		ELSE
			EPRINT "System error: the C Preprocessor 'cpp' not found on this system! Exiting..."
		ENDIF
		END 1
	END IF
ELSE
	FEED$ = g_SOURCEFILE$
END IF
' Set current filename
LET g_CURFILE$ = g_SOURCEFILE$

' Initialize
LET total$ = ""
LET g_COUNTER = 0
LET g_TOTAL_LINES = 0

' Register result buffer for LOOP$ function
Save_Main_Var("__b2c__loop_result" & g_STRINGSIGN$, "char*")
Save_Main_Var("__b2c__loop_result", "long")

Save_Main_Var("ERROR", "int")

' Read source program
OPEN FEED$ FOR READING AS g_SOURCEFILE

' Start walking through program
PRINT "\rConverting '", g_SOURCEFILE$, "'... ";

REPEAT
	READLN line$ FROM g_SOURCEFILE

	INCR g_COUNTER

	IF NOT(g_QUIET) THEN PRINT "\rConverting '", g_SOURCEFILE$, "'... ", g_COUNTER, EL$;

	' Line is not empty?
	IF LEN(line$) > 0 THEN

		IF RIGHT$(line$, 1) = CR$ THEN
			EPRINT "\nSystem error: Windows file detected! Remove non-Unix CR line separators first. Exiting..."
			END 1
		ELIF RIGHT$(line$, 2) = " \\" AND LEFT$(CHOP$(line$), 1) != CHR$(39) THEN
			total$ = total$ & LEFT$(line$, LEN(line$) - 2)
		ELSE
			total$ = CHOP$(total$ & line$)
			IF LEFT$(total$, 1) <> "'" THEN
				IF g_DEBUG THEN
					WRITELN "/* line ", g_COUNTER, " \"", g_SOURCEFILE$, "\" */" TO g_CFILE
					WRITELN "/* line ", g_COUNTER, " \"", g_SOURCEFILE$, "\" */" TO g_HFILE
				ELSE
					WRITELN "#line ", g_COUNTER, " \"", g_SOURCEFILE$, "\"" TO g_CFILE
					WRITELN "#line ", g_COUNTER, " \"", g_SOURCEFILE$, "\"" TO g_HFILE
				ENDIF
				Tokenize(total$)
			END IF
			LET total$ = ""
		END IF
	ENDIF
UNTIL ENDFILE(g_SOURCEFILE)

CLOSE FILE g_SOURCEFILE

IF g_DEBUG = 1 THEN Debug_Vars

' Finalize main C-file
IF g_CATCH_USED = 1 THEN WRITELN "__B2C__PROGRAM__EXIT:" TO g_CFILE
WRITELN "return(0);" TO g_CFILE
WRITELN "}" TO g_CFILE

' Finalize STRING ARRAY file for DATA
WRITELN " \"\" };" TO STRINGARRAYFILE

' Finalize FLOAT ARRAY file for DATA
WRITELN " 0.0};" TO FLOATARRAYFILE

INCR g_TOTAL_LINES, g_COUNTER
ttime = TIMER-starttime
PRINT MOD(ttime, 1000) FORMAT "%.3ld" TO msec_time$
PRINT "\rConverting '", g_SOURCEFILE$, "'... done, ", g_TOTAL_LINES, " lines were processed in ", FLOOR(ttime/1000), ".", msec_time$, " seconds."

' Include local buffers
IF LEN(g_LOCAL_SBUFFER$) THEN WRITELN g_LOCAL_SBUFFER$ TO g_HFILE

' Include functions and subs
FOR incfiles$ IN g_INCLUDE_FILES$
	IF LEN(incfiles$) > 0 THEN WRITELN "#include \"", incfiles$, CHR$(34) TO g_HFILE
NEXT

' Check if generated source file exists
IF FILEEXISTS(SRCARRAYFILE$) THEN
	WRITELN "#include \"", SRCARRAYFILE$, "\"" TO g_HFILE
	g_TMP_FILES$ = g_TMP_FILES$ & " " & SRCARRAYFILE$
ENDIF

' Close filehandle
CLOSE FILE g_HFILE

' The rest of all generic definitions
WRITELN g_PRAGMA_INCLUDE$ TO g_GENERIC
' Add user include files
IF LEN(g_INCFILES$) THEN WRITELN REPLACE$(g_INCFILES$, "#include", NL$ & "#include") TO g_GENERIC
WRITELN "#include <stdio.h>" TO g_GENERIC
WRITELN "#include <stdlib.h>" TO g_GENERIC
WRITELN "#include <stdarg.h>" TO g_GENERIC
WRITELN "#include <stdint.h>" TO g_GENERIC
WRITELN "#include <libgen.h>" TO g_GENERIC
WRITELN "#include <limits.h>" TO g_GENERIC
WRITELN "#include <float.h>" TO g_GENERIC
WRITELN "#include <sys/time.h>" TO g_GENERIC
WRITELN "#include <sys/stat.h>" TO g_GENERIC
WRITELN "#include <sys/types.h>" TO g_GENERIC
WRITELN "#include <sys/wait.h>" TO g_GENERIC
WRITELN "#include <sys/socket.h>" TO g_GENERIC
WRITELN "#include <sys/utsname.h>" TO g_GENERIC
WRITELN "#include <sys/ioctl.h>" TO g_GENERIC
WRITELN "#include <dirent.h>" TO g_GENERIC
WRITELN "#include <setjmp.h>" TO g_GENERIC
WRITELN "#include <netdb.h>" TO g_GENERIC
IF INSTR(OS$, "BSD") THEN
	WRITELN "#include <netinet/in.h>" TO g_GENERIC
	WRITELN "#define strcat(x, y) __b2c_strlcat(x, y)" TO g_GENERIC
	WRITELN "#define strcpy(x, y) __b2c_strlcpy(x, y)" TO g_GENERIC
ENDIF
WRITELN "#include <arpa/inet.h>" TO g_GENERIC
WRITELN "#include <signal.h>" TO g_GENERIC
IF LEN(g_PRAGMA_REGEX$) THEN
	IF NOT(REGEX(g_PRAGMA_REGEX$, " INCLUDE ")) THEN
		kwd$ = HEAD$(g_PRAGMA_REGEX$, 1)
		IF INSTR(kwd$, "tre") THEN
			WRITELN "#include <tre/regex.h>" TO g_GENERIC
		ELIF INSTR(kwd$, "pcre") THEN
			WRITELN "#include <pcreposix.h>" TO g_GENERIC
		ELIF INSTR(kwd$, "onig") THEN
			WRITELN "#include <onigposix.h>" TO g_GENERIC
		ENDIF
	ELSE
		kwd$ = MID$(g_PRAGMA_REGEX$, INSTR(g_PRAGMA_REGEX$, " INCLUDE ")+9)
		WRITELN "#include ", HEAD$(kwd$, 1) TO g_GENERIC
	ENDIF
ELSE
	WRITELN "#include <regex.h>" TO g_GENERIC
ENDIF
' TLS header
IF LEN(g_INC_TLS$) THEN
	IF REGEX(g_INC_TLS$, " INCLUDE ") THEN
		FOR kwd$ IN MID$(g_INC_TLS$, INSTR(g_INC_TLS$, " INCLUDE ")+9)
			WRITELN "#include ", kwd$ TO g_GENERIC
		NEXT
	ELSE
		WRITELN g_INC_TLS$ TO g_GENERIC
	ENDIF
ENDIF
WRITELN "#include <fcntl.h>" TO g_GENERIC
WRITELN "#include <math.h>" TO g_GENERIC
WRITELN "#include <unistd.h>" TO g_GENERIC
WRITELN "#include <string.h>" TO g_GENERIC
WRITELN "#include <ctype.h>" TO g_GENERIC
WRITELN "#include <wctype.h>" TO g_GENERIC
WRITELN "#include <locale.h>" TO g_GENERIC
WRITELN "#include <dlfcn.h>" TO g_GENERIC
WRITELN "#include <errno.h>" TO g_GENERIC
WRITELN "#include <termios.h>" TO g_GENERIC
WRITELN "#include <time.h>" TO g_GENERIC
WRITELN "#include <fts.h>" TO g_GENERIC
WRITELN "#define ENTRY ENTRY_libc" TO g_GENERIC
WRITELN "#include <search.h>" TO g_GENERIC
WRITELN "#undef ENTRY" TO g_GENERIC
WRITELN "/* Undefine all symbols which happen to be BaCon keywords */" TO g_GENERIC
FOR kwd$ IN SORT$(Stat$ & EXTRACT$(Func$, "\\") & EXTRACT$(Var$, "\\"), "|") STEP "|"
	IF RIGHT$(kwd$, 1) <> "$" AND kwd$ <> "NULL" THEN WRITELN "#undef ", kwd$ TO g_GENERIC
NEXT

WRITELN "/* Declarations for internal variables */" TO g_GENERIC
WRITELN "jmp_buf __b2c__jump;" TO g_GENERIC
WRITELN "int __b2c__trap = 1;" TO g_GENERIC
WRITELN "int __b2c__catch_set_backup = 0, __b2c__catch_set = 0;" TO g_GENERIC
WRITELN "void (*__b2c__error_callback)(char*, char*, long) = NULL;" TO g_GENERIC
WRITELN "int __b2c__option_compare = 0;" TO g_GENERIC
WRITELN "int __b2c__option_quoted = 1;" TO g_GENERIC
WRITELN "int __b2c__option_dq = 34;" TO g_GENERIC
WRITELN "int __b2c__option_esc = 92;" TO g_GENERIC
WRITELN "int __b2c__option_utf8 = 0;" TO g_GENERIC
WRITELN "int __b2c__option_proper = 0;" TO g_GENERIC
WRITELN "int __b2c__option_error = 1;" TO g_GENERIC
WRITELN "int __b2c__option_tls = 0;" TO g_GENERIC
WRITELN "char *__b2c__option_delim = \" \";" TO g_GENERIC
WRITELN "int __b2c__option_memstream = 0;" TO g_GENERIC
WRITELN "int __b2c__option_startpoint = 0;" TO g_GENERIC
WRITELN "int __b2c__option_open = O_RDWR|O_NOCTTY|O_SYNC;" TO g_GENERIC
WRITELN "int __b2c__collapse = 0;" TO g_GENERIC
WRITELN "int __b2c__break_ctr = 0;" TO g_GENERIC
WRITELN "int __b2c__break_flag = 0;" TO g_GENERIC
WRITELN "char __b2c__chop_default[] = \"\\r\\n\\t \";" TO g_GENERIC
WRITELN "int __b2c__stringarray_ptr = 0;" TO g_GENERIC
WRITELN "int __b2c__floatarray_ptr = 0;" TO g_GENERIC
WRITELN "long __b2c__ctr;" TO g_GENERIC
WRITELN "char EmptyString[1] = { 0 };" TO g_GENERIC
' Save the max amount of parallel string buffers
WRITELN "#define __b2c_STRING_FUNC (", g_STRING_FUNC, ")" TO g_GENERIC
WRITELN "jmp_buf __b2c__gosub_buffer[", g_MAX_RBUFFERS, "];" TO g_GENERIC
WRITELN "int __b2c__gosub_buffer_ptr = -1;" TO g_GENERIC
WRITELN "char* __b2c__loop_result", g_STRINGSIGN$, " = NULL;" TO g_GENERIC
WRITELN "long __b2c__loop_result = 0;" TO g_GENERIC
WRITELN "jmp_buf __b2c__data_jump, __b2c__loop1, __b2c__loop2;" TO g_GENERIC
WRITELN "char *__b2c__assign = NULL;" TO g_GENERIC
WRITELN "int __b2c__counter;" TO g_GENERIC
WRITELN "char **__b2c__stack = NULL;" TO g_GENERIC
WRITELN "void **__b2c__twalk_array = NULL; int __b2c__twalk_idx = 0;" TO g_GENERIC
WRITELN "extern char *__b2c__stringarray[];" TO g_GENERIC
WRITELN "extern double __b2c__floatarray[];" TO g_GENERIC
WRITELN "unsigned long __b2c__ptrlow = ULONG_MAX;" TO g_GENERIC
WRITELN "unsigned long __b2c__ptrhgh = 0;" TO g_GENERIC
WRITELN "char *__b2c__me_var", g_STRINGSIGN$, " = NULL;" TO g_GENERIC
WRITELN "/* Declarations for BaCon variables */" TO g_GENERIC
WRITELN "char *ARGUMENT", g_STRINGSIGN$, " = NULL;" TO g_GENERIC
WRITELN "int ERROR = 0;" TO g_GENERIC
WRITELN "int RETVAL = 0;" TO g_GENERIC
WRITELN "int REGLEN = 0;" TO g_GENERIC
WRITELN "int SP = 0;" TO g_GENERIC
WRITELN "char VERSION", g_STRINGSIGN$, "[] = \"", g_VERSION$, "\";" TO g_GENERIC
' Prototypes for functions
WRITELN "/* Prototypes for internal functions */" TO g_GENERIC
WRITELN "int __b2c__strcmp(const char*, const char*);" TO g_GENERIC
WRITELN "char *__b2c__strdup(const char*);" TO g_GENERIC
WRITELN "char *__b2c__strndup(const char*, size_t);" TO g_GENERIC
WRITELN "void* __b2c_str_realloc(char*, size_t);" TO g_GENERIC
WRITELN "long __b2c__delim_engine(int, long*, char*, char*, long);" TO g_GENERIC
IF INSTR(OS$, "BSD") THEN
	WRITELN "char *__b2c_strlcat(char*, const char*);" TO g_GENERIC
	WRITELN "char *__b2c_strlcpy(char*, const char*);" TO g_GENERIC
ENDIF
WRITELN "/* Prototypes for BaCon functions */" TO g_GENERIC
WRITELN "char *ERR", g_STRINGSIGN$, "(int);" TO g_GENERIC
WRITELN "int __b2c_utf8_conv(int,char*);" TO g_GENERIC
WRITELN "char* __b2c_Copy_String(char*,char*);" TO g_GENERIC
WRITELN "void __b2c_Swap_String(char**,char**);" TO g_GENERIC
WRITELN "unsigned long __b2c__len(const char*);" TO g_GENERIC
WRITELN "unsigned long __b2c__ulen(int,char*,char*,char*,int);" TO g_GENERIC
WRITELN "unsigned long __b2c__blen(int,char*,char*,char*,long,int);" TO g_GENERIC
WRITELN "unsigned long __b2c__ucs2_clen(int,char*,char*,char*,int);" TO g_GENERIC
WRITELN "/* Internal macro definitions */" TO g_GENERIC
WRITELN "#define __b2c__MEMTYPE char" TO g_GENERIC
WRITELN "#define __b2c__STRCMP __b2c__strcmp" TO g_GENERIC
WRITELN "#define __b2c__BUFOFFSET 9" TO g_GENERIC
WRITELN "#define __b2c__INRANGE(x) ((unsigned long)x > __b2c__ptrlow && (unsigned long)x < __b2c__ptrhgh ? 1 : 0)" TO g_GENERIC
WRITELN "#define __b2c__SETRANGE(x) if((unsigned long)x < __b2c__ptrlow) { __b2c__ptrlow = (unsigned long)(x-1); } if((unsigned long)x > __b2c__ptrhgh) { __b2c__ptrhgh = (unsigned long)(x+__b2c__BUFOFFSET+1); }" TO g_GENERIC
WRITELN "#define __b2c__STRFREE(x) ( x!=NULL && (uintptr_t)x&1 ? free(x-__b2c__BUFOFFSET) : free(x) )" TO g_GENERIC
WRITELN "#define __b2c__SETLEN(x,y) *(uint32_t*)(x-__b2c__BUFOFFSET) = y;" TO g_GENERIC
WRITELN "#define __b2c__MEMDUP(x, y) memcpy(malloc(x), &y, x)" TO g_GENERIC
WRITELN "#define __b2c__FUNCSELECT2(_1, _2, x, ...) x" TO g_GENERIC
WRITELN "#define __b2c__FUNCSELECT3(_1, _2, _3, x, ...) x" TO g_GENERIC
WRITELN "#define __b2c__FUNCSELECT4(_1, _2, _3, _4, x, ...) x" TO g_GENERIC
WRITELN "#define __b2c__FUNCSELECT5(_1, _2, _3, _4, _5, x, ...) x" TO g_GENERIC
WRITELN "#define __b2c__FUNCSELECT10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _0, x, ...) x" TO g_GENERIC
WRITELN "#define COMPILED_BY_WHICH_BACON", g_STRINGSIGN$, " ", CHR$(34), "BaCon executable ", g_VERSION$, CHR$(34) TO g_GENERIC
WRITELN "#define RUNTIMEERROR(a, x, y, z) do { if(__b2c__option_error) { fprintf(stderr, \"Runtime error: statement '%s' at line %d in '%s': %s\\n\", a, x, y, ERR", g_STRINGSIGN$, "(z)); exit(z); } if(__b2c__error_callback){(*__b2c__error_callback)(a,y,x);} } while(0)" TO g_GENERIC
WRITELN "#define RUNTIMEFERR(a, x, y, z) do { if(__b2c__option_error) { fprintf(stderr, \"Runtime error: function '%s' at line %d in '%s': %s\\n\", a, z, y, ERR", g_STRINGSIGN$, "(x)); exit(x); } if(__b2c__error_callback){(*__b2c__error_callback)(a,y,z);} } while(0)" TO g_GENERIC
WRITELN "#define RUNTIMEDEBUG(x, y, z) (__b2c__getch() == 27 ? fprintf(stderr, \"TRACE OFF - exiting trace mode.\\n\") && __b2c__stop_program() : fprintf(stderr, \"File '%s' line %d: %s\\n\", #x, y, z)", g_MONITOR$, " )" TO g_GENERIC
WRITELN "int __b2c__stop_program(void) { exit(EXIT_SUCCESS); return(1); }" TO g_GENERIC
WRITELN "/* BaCon functions */" TO g_GENERIC
WRITELN "#define ABS(x) (((x) < 0) ? -(x) : (x))" TO g_GENERIC
WRITELN "#define ACOS(x) acos((double)x)" TO g_GENERIC
WRITELN "#define ADDRESS(x) (uintptr_t)(&x)" TO g_GENERIC
WRITELN "#define __b2c__ALIGN3(x, y, z) __b2c__align(__LINE__, __FILE__, x, y, z, 0)" TO g_GENERIC
WRITELN "#define __b2c__ALIGN4(x, y, z, f) __b2c__align(__LINE__, __FILE__, x, y, z, f)" TO g_GENERIC
WRITELN "#define ALIGN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__ALIGN4, __b2c__ALIGN3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__AMOUNT1(x) __b2c__amount(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__AMOUNT2(x, y) __b2c__amount(x, y)" TO g_GENERIC
WRITELN "#define AMOUNT(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__AMOUNT2, __b2c__AMOUNT1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define AND &&" TO g_GENERIC
WRITELN "#define __b2c__APPEND3(x, y, z) __b2c__append(x, y, z, NULL)" TO g_GENERIC
WRITELN "#define __b2c__APPEND4(x, y, z, f) __b2c__append(x, y, z, f)" TO g_GENERIC
WRITELN "#define APPEND", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__APPEND4, __b2c__APPEND3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define ASC(x) (unsigned char)*x" TO g_GENERIC
WRITELN "#define ASIN(x) asin((double)x)" TO g_GENERIC
WRITELN "#define ATN(x) atan((double)x)" TO g_GENERIC
WRITELN "#define ATN2(x,y) atan2((double)x,(double)y)" TO g_GENERIC
WRITELN "#define B64DEC", g_STRINGSIGN$, "(x) __b2c__b64dec(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define __b2c__B64ENC1(x) __b2c__b64enc(x, 0)" TO g_GENERIC
WRITELN "#define __b2c__B64ENC2(x, y) __b2c__b64enc((char*)x, y)" TO g_GENERIC
WRITELN "#define B64ENC", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__B64ENC2, __b2c__B64ENC1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__BASENAME1(x) __b2c__dirname(__LINE__, __FILE__, 1, x, 0)" TO g_GENERIC
WRITELN "#define __b2c__BASENAME2(x, y) __b2c__dirname(__LINE__, __FILE__, 1, x, y)" TO g_GENERIC
WRITELN "#define BASENAME", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__BASENAME2, __b2c__BASENAME1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define BIN", g_STRINGSIGN$, "(x) __b2c__bin(sizeof(__b2c__MEMTYPE), x)" TO g_GENERIC
WRITELN "#define BIT(x) __b2c__bit(x)" TO g_GENERIC
WRITELN "#define BLOAD(x) (void*)__b2c__load(1, __LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define __b2c__BYTELEN2(x, y) __b2c__blen(__LINE__, __FILE__, \"BYTELEN\", x, y, 0)" TO g_GENERIC
WRITELN "#define __b2c__BYTELEN3(x, y, z) __b2c__blen(__LINE__, __FILE__, \"BYTELEN\", x, y, z)" TO g_GENERIC
WRITELN "#define BYTELEN(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__BYTELEN3, __b2c__BYTELEN2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define CA", g_STRINGSIGN$, "(x) __b2c__ca(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define CN", g_STRINGSIGN$, "(x) __b2c__cn(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define CIPHER", g_STRINGSIGN$, "(x) __b2c__cipher(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define VERIFY(x, y) ((SSL*)x == NULL ? -1 : (long)SSL_get_verify_result((SSL*)x) )" TO g_GENERIC
WRITELN "#define ACCEPT(x) __b2c__accept(__LINE__, __FILE__, __b2c__caprivate, __b2c__caserver, x)" TO g_GENERIC
WRITELN "#define CEIL(x) (double)ceil(x)" TO g_GENERIC
WRITELN "#define __b2c__CHANGE3(x, y, z) __b2c__change(x, y, z, NULL)" TO g_GENERIC
WRITELN "#define __b2c__CHANGE4(x, y, z, f) __b2c__change(x, y, z, f)" TO g_GENERIC
WRITELN "#define CHANGE", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__CHANGE4, __b2c__CHANGE3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__CHOP1(x) __b2c__chop(x, NULL, 0)" TO g_GENERIC
WRITELN "#define __b2c__CHOP2(x, y) __b2c__chop(x, y, 0)" TO g_GENERIC
WRITELN "#define __b2c__CHOP3(x, y, z) __b2c__chop(x, y, z)" TO g_GENERIC
WRITELN "#define CHOP", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__CHOP3, __b2c__CHOP2, __b2c__CHOP1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define CHR", g_STRINGSIGN$, "(x) __b2c__asc2char(x)" TO g_GENERIC
WRITELN "#define UTF8", g_STRINGSIGN$, "(x) __b2c__asc2utf8(x)" TO g_GENERIC
WRITELN "#define CL", g_STRINGSIGN$, " \"\\033[2K\"" TO g_GENERIC
WRITELN "#define CMDLINE(x) __b2c__getopt(argc, argv, x)" TO g_GENERIC
WRITELN "#define COIL", g_STRINGSIGN$, "(...) ( !setjmp(__b2c__loop1) ? __b2c__loop_helper(__b2c__loop2) : __b2c__loop_result", g_STRINGSIGN$, " )" TO g_GENERIC
WRITELN "#define __b2c__COLLAPSE1(x) __b2c__collapse_func(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__COLLAPSE2(x, y) __b2c__collapse_func(x, y)" TO g_GENERIC
WRITELN "#define COLLAPSE", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__COLLAPSE2, __b2c__COLLAPSE1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define COLUMNS __b2c__screen(0)" TO g_GENERIC
WRITELN "#define CONCAT", g_STRINGSIGN$, "(...) __b2c__concat(sizeof((const char*[]) {__VA_ARGS__}) / sizeof(char*), __VA_ARGS__)" TO g_GENERIC
WRITELN "#define COS(x) cos((double)x)" TO g_GENERIC
WRITELN "#define COUNT(x, y) ((x) != NULL ? __b2c__count(__LINE__, __FILE__, x, y) : 0)" TO g_GENERIC
WRITELN "#define CR", g_STRINGSIGN$, " \"\\r\"" TO g_GENERIC
WRITELN "#define CURDIR", g_STRINGSIGN$, " __b2c__curdir()" TO g_GENERIC
WRITELN "#define __b2c__CUT3(x, y, z) __b2c__cut(x, y, z, NULL)" TO g_GENERIC
WRITELN "#define __b2c__CUT4(x, y, z, f) __b2c__cut(x, y, z, f)" TO g_GENERIC
WRITELN "#define CUT", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__CUT4, __b2c__CUT3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define DAY(x) __b2c__time(x, 1)" TO g_GENERIC
WRITELN "#define __b2c__DEC1(x) __b2c__hex2dec(__LINE__, __FILE__, x, 0)" TO g_GENERIC
WRITELN "#define __b2c__DEC2(x, y) __b2c__hex2dec(__LINE__, __FILE__, x, y)" TO g_GENERIC
WRITELN "#define DEC(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__DEC2, __b2c__DEC1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define DEG(x) (x*180/PI)" TO g_GENERIC
WRITELN "#define __b2c__DEL2(x, y) __b2c__del(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__DEL3(x, y, z) __b2c__del(x, y, z)" TO g_GENERIC
WRITELN "#define DEL", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__DEL3, __b2c__DEL2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define DELIM", g_STRINGSIGN$, "(x, y, z) __b2c__delim(x, y, z)" TO g_GENERIC
WRITELN "#define DIRNAME", g_STRINGSIGN$, "(x) __b2c__dirname(__LINE__, __FILE__, 2, x, 0)" TO g_GENERIC
WRITELN "#define DLE", g_STRINGSIGN$, " \"\\r\\n\"" TO g_GENERIC
WRITELN "#define EL", g_STRINGSIGN$, " \"\\033[0K\"" TO g_GENERIC
WRITELN "#define ENDFILE(x) feof(x)" TO g_GENERIC
WRITELN "#define EQ ==" TO g_GENERIC
WRITELN "#define EQUAL(x, y) ((x) != NULL && (y) != NULL ? !__b2c__STRCMP(x, y) : 0)" TO g_GENERIC
WRITELN "#define ESCAPE", g_STRINGSIGN$, "(x) __b2c__escape(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define EVAL(x, y, z, q) __b2c__eval(__LINE__, __FILE__, x, y, z, q)" TO g_GENERIC
WRITELN "#define EVEN(x) (((long)(x) % 2 == 0) ? 1 : 0)" TO g_GENERIC
WRITELN "#define __b2c__EXCHANGE3(x, y, z) __b2c__exchange(x, y, z, NULL)" TO g_GENERIC
WRITELN "#define __b2c__EXCHANGE4(x, y, z, f) __b2c__exchange(x, y, z, f)" TO g_GENERIC
WRITELN "#define EXCHANGE", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__EXCHANGE4, __b2c__EXCHANGE3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__EXEC1(x) __b2c__exec(0, __LINE__, __FILE__, x, NULL, 0)" TO g_GENERIC
WRITELN "#define __b2c__EXEC2(x, y) __b2c__exec(0, __LINE__, __FILE__, x, y, 0)" TO g_GENERIC
WRITELN "#define __b2c__EXEC3(x, y, z) __b2c__exec(0, __LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define EXEC", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__EXEC3, __b2c__EXEC2, __b2c__EXEC1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define EXP(x) exp((double)x)" TO g_GENERIC
WRITELN "#define __b2c__EXPLODE1(x) __b2c__explode(__LINE__, __FILE__, x, 1, NULL)" TO g_GENERIC
WRITELN "#define __b2c__EXPLODE2(x, y) __b2c__explode(__LINE__, __FILE__, x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__EXPLODE3(x, y, z) __b2c__explode(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define EXPLODE", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__EXPLODE3, __b2c__EXPLODE2, __b2c__EXPLODE1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__EXTRACT2(x, y) __b2c__extract(__LINE__, __FILE__, x, y, 0)" TO g_GENERIC
WRITELN "#define __b2c__EXTRACT3(x, y, z) __b2c__extract(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define EXTRACT", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__EXTRACT3, __b2c__EXTRACT2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define FALSE 0" TO g_GENERIC
WRITELN "#define FILEEXISTS(x) (x != NULL ? !access(x, F_OK) : 0)" TO g_GENERIC
WRITELN "#define FILELEN(x) __b2c__filelen(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define FILETIME(x, y) __b2c__filetime(__LINE__, __FILE__, x, y)" TO g_GENERIC
WRITELN "#define FILETYPE(x) __b2c__filetype(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define FILL", g_STRINGSIGN$, "(x, y) ((y) >= 0 && (y) <= 0x10FFFF ? __b2c__fill(x, y) : EmptyString)" TO g_GENERIC
WRITELN "#define FIND(x, y, z) __b2c__find(x, y, (void*)z)" TO g_GENERIC
WRITELN "#define __b2c__FIRST2(x, y) __b2c__first(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__FIRST3(x, y, z) __b2c__first(x, y, z)" TO g_GENERIC
WRITELN "#define FIRST", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__FIRST3, __b2c__FIRST2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__FLATTEN1(x) __b2c__flatten(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__FLATTEN2(x, y) __b2c__flatten(x, y)" TO g_GENERIC
WRITELN "#define FLATTEN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__FLATTEN2, __b2c__FLATTEN1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define FLOATING double" TO g_GENERIC
WRITELN "#define FLOOR(x) (long)floor(x)" TO g_GENERIC
WRITELN "#define FORK fork()" TO g_GENERIC
WRITELN "#define FP(x) (void*)(&x)" TO g_GENERIC
WRITELN "#define GE >=" TO g_GENERIC
WRITELN "#define GETENVIRON", g_STRINGSIGN$, "(x) ((x) != NULL ? __b2c__getenv(x) : (char*)\"null\")" TO g_GENERIC
WRITELN "#define GETKEY __b2c__getch()" TO g_GENERIC
WRITELN "#define GETPEER", g_STRINGSIGN$, "(x) __b2c__getpeer(__LINE__, __FILE__, (uintptr_t)x)" TO g_GENERIC
WRITELN "#define GETX __b2c__getxy(0)" TO g_GENERIC
WRITELN "#define GETY __b2c__getxy(1)" TO g_GENERIC
WRITELN "#define GUIDEFINE(x) __b2c__guiDefine()" TO g_GENERIC
WRITELN "#define __b2c__GUIEVENT1(x) __b2c__guiExecute(x, 0)" TO g_GENERIC
WRITELN "#define __b2c__GUIEVENT2(x, y) __b2c__guiExecute(x, y)" TO g_GENERIC
WRITELN "#define GUIEVENT", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__GUIEVENT2, __b2c__GUIEVENT1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__GUIFN1(id, x, func) func(GUIWIDGET(id, x))" TO g_GENERIC
WRITELN "#define __b2c__GUIFN2(id, x, func, ...) func(GUIWIDGET(id, x), __VA_ARGS__)" TO g_GENERIC
WRITELN "#define GUIFN(...) __b2c__FUNCSELECT10(__VA_ARGS__, __b2c__GUIFN2, __b2c__GUIFN2, __b2c__GUIFN2, __b2c__GUIFN2, __b2c__GUIFN2, __b2c__GUIFN2, __b2c__GUIFN2, __b2c__GUIFN1)(__VA_ARGS__)" TO g_GENERIC
IF g_WHICH_GUI = 2 THEN
	WRITELN "#define GUIWIDGET(id, x) __b2c_get_by_name(id, x)" TO g_GENERIC
	WRITELN "#define GUIGET(id, x, p, q) (*(q)) = getCDK ## p( ( GUIWIDGET(id, x) == NULL ? (void*)(uintptr_t)fprintf(stderr, \"Runtime error: function 'GUIGET' at line %d in '%s': %s\\n\", __LINE__, __FILE__, ERR", g_STRINGSIGN$, "(42)) : GUIWIDGET(id, x) ) )" TO g_GENERIC
	WRITELN "#define GUISET(id, x, p, ...) ( GUIWIDGET(id, x) == NULL ? fprintf(stderr, \"Runtime error: function 'GUISET' at line %d in '%s': %s\\n\", __LINE__, __FILE__, ERR", g_STRINGSIGN$, "(42)) : setCDK ## p(GUIWIDGET(id, x), __VA_ARGS__) )" TO g_GENERIC
ELIF g_WHICH_GUI = 1 OR g_WHICH_GUI = 3 THEN
	WRITELN "#define GUIWIDGET(id, x) __b2c_get_by_name(id, x)" TO g_GENERIC
	WRITELN "#define GUIGET(id, x, ...) ( GUIWIDGET(id, x) == NULL ? fprintf(stderr, \"Runtime error: function 'GUIGET' at line %d in '%s': %s\\n\", __LINE__, __FILE__, ERR", g_STRINGSIGN$, "(42)) : g_object_get(G_OBJECT(GUIWIDGET(id, x)), __VA_ARGS__, NULL) )" TO g_GENERIC
	WRITELN "#define GUISET(id, x, ...) ( GUIWIDGET(id, x) == NULL ? fprintf(stderr, \"Runtime error: function 'GUISET' at line %d in '%s': %s\\n\", __LINE__, __FILE__, ERR", g_STRINGSIGN$, "(42)) : g_object_set(G_OBJECT(GUIWIDGET(id, x)), __VA_ARGS__, NULL) )" TO g_GENERIC
ELSE
	WRITELN "#define GUIWIDGET(id, x) XtNameToWidget((Widget)id, \"*\" x)" TO g_GENERIC
	WRITELN "#define GUIGET(id, x, ...) ( GUIWIDGET(id, x) == NULL ? fprintf(stderr, \"Runtime error: function 'GUIGET' at line %d in '%s': %s\\n\", __LINE__, __FILE__, ERR", g_STRINGSIGN$, "(42)) : XtVaGetValues(GUIWIDGET(id, x), __VA_ARGS__, NULL) )" TO g_GENERIC
	WRITELN "#define GUISET(id, x, ...) ( GUIWIDGET(id, x) == NULL ? fprintf(stderr, \"Runtime error: function 'GUISET' at line %d in '%s': %s\\n\", __LINE__, __FILE__, ERR", g_STRINGSIGN$, "(42)) : XtVaSetValues(GUIWIDGET(id, x), __VA_ARGS__, NULL) )" TO g_GENERIC
ENDIF
WRITELN "#define GT >" TO g_GENERIC
WRITELN "#define __b2c__HASDELIM1(x) __b2c__hasdelim(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__HASDELIM2(x, y) __b2c__hasdelim(x, y)" TO g_GENERIC
WRITELN "#define HASDELIM(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__HASDELIM2, __b2c__HASDELIM1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__HASH1(x) __b2c__HashFNV1a((char*)x, 0)" TO g_GENERIC
WRITELN "#define __b2c__HASH2(x, y) __b2c__HashFNV1a((char*)x, y)" TO g_GENERIC
WRITELN "#define HASH(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__HASH2, __b2c__HASH1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__HEAD2(x, y) __b2c__head(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__HEAD3(x, y, z) __b2c__head(x, y, z)" TO g_GENERIC
WRITELN "#define HEAD", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__HEAD3, __b2c__HEAD2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define HEX", g_STRINGSIGN$, "(x) __b2c__dec2hex(x)" TO g_GENERIC
WRITELN "#define HOST", g_STRINGSIGN$, "(x) __b2c__nethost(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define HOSTNAME", g_STRINGSIGN$, " __b2c__hostname(__LINE__, __FILE__)" TO g_GENERIC
WRITELN "#define HOUR(x) __b2c__time(x, 4)" TO g_GENERIC
WRITELN "#define __b2c__IIF2(x, y) (x ? y : 0)" TO g_GENERIC
WRITELN "#define __b2c__IIF3(x, y, z) (x ? y : z)" TO g_GENERIC
WRITELN "#define IIF(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__IIF3, __b2c__IIF2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__IIFS2(x, y) (char*)(x ? y : EmptyString)" TO g_GENERIC
WRITELN "#define __b2c__IIFS3(x, y, z) (char*)(x ? y : z)" TO g_GENERIC
WRITELN "#define IIF", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__IIFS3, __b2c__IIFS2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__INBETWEEN3(x, y, z) __b2c__inbetween(0, x, y, z, 0)" TO g_GENERIC
WRITELN "#define __b2c__INBETWEEN4(x, y, z, f) __b2c__inbetween(0, x, y, z, f)" TO g_GENERIC
WRITELN "#define INBETWEEN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__INBETWEEN4, __b2c__INBETWEEN3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__INDEX4(r, t, x, y) __b2c__index(__LINE__, __FILE__, r+", g_OPTION_BASE, ", t, (void*)x, 0, y)" TO g_GENERIC
WRITELN "#define __b2c__INDEX5(r, t, x, y, z) __b2c__index(__LINE__, __FILE__, r+", g_OPTION_BASE, ", t, (void*)x, z, y)" TO g_GENERIC
WRITELN "#define INDEX(...) __b2c__FUNCSELECT5(__VA_ARGS__, __b2c__INDEX5, __b2c__INDEX4)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define INSERT", g_STRINGSIGN$, "(x, y, z) __b2c__insert(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define __b2c__INSTR2(x, y) __b2c__instr(__LINE__, __FILE__, x, y, -1)" TO g_GENERIC
WRITELN "#define __b2c__INSTR3(x, y, z) __b2c__instr(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define INSTR(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__INSTR3, __b2c__INSTR2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__INSTRREV2(x, y) __b2c__instrrev(__LINE__, __FILE__, x, y, -1)" TO g_GENERIC
WRITELN "#define __b2c__INSTRREV3(x, y, z) __b2c__instrrev(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define INSTRREV(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__INSTRREV3, __b2c__INSTRREV2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define INT(x) lrint((double)x)" TO g_GENERIC
WRITELN "#define INTL", g_STRINGSIGN$, "(x) gettext(x)" TO g_GENERIC
WRITELN "#define IS ==" TO g_GENERIC
WRITELN "#define ISASCII(x) __b2c__isascii(x)" TO g_GENERIC
WRITELN "#define ISFALSE(x) ((x) == 0)" TO g_GENERIC
WRITELN "#define ISKEY(x, ...) (__b2c__hash_find_key_do(__b2c__assoc_ ## x, 0, __b2c__KEYCOLLECT(__VA_ARGS__)) == NULL ? 0 : 1)" TO g_GENERIC
WRITELN "#define ISNOT !=" TO g_GENERIC
WRITELN "#define __b2c__ISTOKEN2(x, y) __b2c__istoken(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__ISTOKEN3(x, y, z) __b2c__istoken(x, y, z)" TO g_GENERIC
WRITELN "#define ISTOKEN(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__ISTOKEN3, __b2c__ISTOKEN2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define ISTRUE(x) ((x) != 0)" TO g_GENERIC
WRITELN "#define ISUTF8(x) __b2c__isutf8(x)" TO g_GENERIC
WRITELN "#define LCASE", g_STRINGSIGN$, "(x) __b2c__lcase(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define LE <=" TO g_GENERIC
WRITELN "#define __b2c__LEFT1(x) __b2c__left(__LINE__, __FILE__, x, 1)" TO g_GENERIC
WRITELN "#define __b2c__LEFT2(x, y) __b2c__left(__LINE__, __FILE__, x, y)" TO g_GENERIC
WRITELN "#define LEFT", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__LEFT2, __b2c__LEFT1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define LEN(x) (__b2c__option_utf8 ? __b2c__ulen(__LINE__, __FILE__, \"LEN\", (char*)x, -1) : __b2c__len(x))" TO g_GENERIC
WRITELN "#define __b2c__ULEN1(x) __b2c__ulen(__LINE__, __FILE__, \"ULEN\", (char*)x, -1)" TO g_GENERIC
WRITELN "#define __b2c__ULEN2(x, y) __b2c__ulen(__LINE__, __FILE__, \"ULEN\", (char*)x, y)" TO g_GENERIC
WRITELN "#define ULEN(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__ULEN2, __b2c__ULEN1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__LAST2(x, y) __b2c__last(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__LAST3(x, y, z) __b2c__last(x, y, z)" TO g_GENERIC
WRITELN "#define LAST", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__LAST3, __b2c__LAST2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define LINENO __LINE__" TO g_GENERIC
WRITELN "#define LOAD", g_STRINGSIGN$, "(x) __b2c__load(0, __LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define LOG(x) log((double)x)" TO g_GENERIC
WRITELN "#define LOOP", g_STRINGSIGN$, "(...) ( !setjmp(__b2c__loop1) ? __b2c__loop_helper(__b2c__loop2) : __b2c__loop_result", g_STRINGSIGN$, " )" TO g_GENERIC
WRITELN "#define LOOP(...) ( !setjmp(__b2c__loop1) ? __b2c__loop_helper2(__b2c__loop2) : __b2c__loop_result )" TO g_GENERIC
WRITELN "#define LT <" TO g_GENERIC
WRITELN "#define __b2c__MATCH2(x, y) __b2c__match(x, y, -1, NULL)" TO g_GENERIC
WRITELN "#define __b2c__MATCH3(x, y, z) __b2c__match(x, y, z, NULL)" TO g_GENERIC
WRITELN "#define __b2c__MATCH4(x, y, z, f) __b2c__match(x, y, z, f)" TO g_GENERIC
WRITELN "#define MATCH(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__MATCH4, __b2c__MATCH3, __b2c__MATCH2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define MAX(x, y) fmax(x, y)" TO g_GENERIC
WRITELN "#define MAX", g_STRINGSIGN$, "(x, y) __b2c__max_str(x, y)" TO g_GENERIC
WRITELN "#define MAXNUM(x) (x)POW(2, SIZEOF(x)*8)" TO g_GENERIC
IF INSTR(OS$, "SunOS") OR INSTR(OS$, "OSF1") THEN
	WRITELN "#define MAXRANDOM 2147483647" TO g_GENERIC
ELSE
	WRITELN "#define MAXRANDOM RAND_MAX" TO g_GENERIC
END IF
WRITELN "#define ME", g_STRINGSIGN$, " __b2c__me_var", g_STRINGSIGN$ TO g_GENERIC
WRITELN "#define MEMCHECK(x) !(__b2c__memory__check((char*)x, sizeof(__b2c__MEMTYPE)))" TO g_GENERIC
WRITELN "#define MEMORY(x) (calloc(x+__b2c__option_memstream, sizeof(__b2c__MEMTYPE)))" TO g_GENERIC
WRITELN "#define MEMTELL(x) (long)x" TO g_GENERIC
WRITELN "#define __b2c__MERGE1(x) __b2c__merge(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__MERGE2(x, y) __b2c__merge(x, y)" TO g_GENERIC
WRITELN "#define MERGE", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__MERGE2, __b2c__MERGE1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__MID2(x, y) __b2c__mid(__LINE__, __FILE__, x, y, -1)" TO g_GENERIC
WRITELN "#define __b2c__MID3(x, y, z) __b2c__mid(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define MID", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__MID3, __b2c__MID2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define MIN(x, y) fmin(x, y)" TO g_GENERIC
WRITELN "#define MIN", g_STRINGSIGN$, "(x, y) __b2c__min_str(x, y)" TO g_GENERIC
WRITELN "#define MINUTE(x) __b2c__time(x, 5)" TO g_GENERIC
WRITELN "#define MOD(x, y) ((long)(x) % (long)(y))" TO g_GENERIC
WRITELN "#define MONTH(x) __b2c__time(x, 2)" TO g_GENERIC
WRITELN "#define MONTH", g_STRINGSIGN$, "(x) __b2c__datename(x, 2)" TO g_GENERIC
WRITELN "#define MYPID getpid()" TO g_GENERIC
WRITELN "#define NE !=" TO g_GENERIC
WRITELN "#define NL", g_STRINGSIGN$, " \"\\n\"" TO g_GENERIC
WRITELN "#define NNTL", g_STRINGSIGN$, "(x,y,z) ngettext(x,y,z)" TO g_GENERIC
WRITELN "#define NOT(x) (!(x))" TO g_GENERIC
WRITELN "#define NOW (long)time(NULL)" TO g_GENERIC
WRITELN "#define NRKEYS(x) __b2c__hash_nrkeys(__b2c__assoc_ ## x)" TO g_GENERIC
WRITELN "#define NUMBER long" TO g_GENERIC
WRITELN "#define __b2c__OBTAIN1(x) __b2c__hash_obtain(__b2c__assoc_ ## x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__OBTAIN2(x, y) __b2c__hash_obtain(__b2c__assoc_ ## x, y)" TO g_GENERIC
WRITELN "#define __b2c__OBTAIN3(x, y, z) __b2c__hash_obtain_by_sort(__LINE__, __FILE__, __b2c__assoc_ ## x, y, z, __b2c__obtain_type_ ## x)" TO g_GENERIC
WRITELN "#define OBTAIN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__OBTAIN3, __b2c__OBTAIN2, __b2c__OBTAIN1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define ODD(x) (((long)(x) % 2 != 0) ? 1 : 0)" TO g_GENERIC
WRITELN "#define OR ||" TO g_GENERIC
WRITELN "#define OS", g_STRINGSIGN$, " __b2c__os(__LINE__, __FILE__)" TO g_GENERIC
WRITELN "#define __b2c__OUTBETWEEN3(x, y, z) __b2c__inbetween(1, x, y, z, 0)" TO g_GENERIC
WRITELN "#define __b2c__OUTBETWEEN4(x, y, z, f) __b2c__inbetween(1, x, y, z, f)" TO g_GENERIC
WRITELN "#define OUTBETWEEN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__OUTBETWEEN4, __b2c__OUTBETWEEN3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define PEEK(x) (__b2c__peek_check(__LINE__, __FILE__, (char*)x, sizeof(__b2c__MEMTYPE)) == 0 ? *(__b2c__MEMTYPE *)(x) : 0)" TO g_GENERIC
WRITELN "#define PI 3.14159265358979323846" TO g_GENERIC
WRITELN "#define POW(x, y) pow((double)x, (double)y)" TO g_GENERIC
WRITELN "#define __b2c__PROPER1(x) __b2c__proper(__LINE__, __FILE__, x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__PROPER2(x, y) __b2c__proper(__LINE__, __FILE__, x, y)" TO g_GENERIC
WRITELN "#define PROPER", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__PROPER2, __b2c__PROPER1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define RAD(x) (x*PI/180)" TO g_GENERIC
WRITELN "#define RANDOM(x) ((x) != 0 ? random()/(MAXRANDOM/(x)) : 0)" TO g_GENERIC
WRITELN "#define REALPATH", g_STRINGSIGN$, "(x) __b2c__dirname(__LINE__, __FILE__, 0, x, 0)" TO g_GENERIC
WRITELN "#define REAP(x) waitpid(x, NULL, WNOHANG)" TO g_GENERIC
WRITELN "#define REGEX(x, y) __b2c__regex(__LINE__, __FILE__, x, y)" TO g_GENERIC
WRITELN "#define __b2c__REPLACE3(x, y, z) __b2c__replace(__LINE__, __FILE__, x, y, z, 0)" TO g_GENERIC
WRITELN "#define __b2c__REPLACE4(x, y, z, f) __b2c__replace(__LINE__, __FILE__, x, y, z, f)" TO g_GENERIC
WRITELN "#define REPLACE", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT4(__VA_ARGS__, __b2c__REPLACE4, __b2c__REPLACE3)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__REV1(x) __b2c__rev(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__REV2(x, y) __b2c__rev(x, y)" TO g_GENERIC
WRITELN "#define REV", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__REV2, __b2c__REV1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define REVERSE", g_STRINGSIGN$, "(x) __b2c__reverse(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define __b2c__RIGHT1(x) __b2c__right(__LINE__, __FILE__, x, 1)" TO g_GENERIC
WRITELN "#define __b2c__RIGHT2(x, y) __b2c__right(__LINE__, __FILE__, x, y)" TO g_GENERIC
WRITELN "#define RIGHT", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__RIGHT2, __b2c__RIGHT1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__RIP2(x, y) __b2c__rip(__LINE__, __FILE__, x, y, -1)" TO g_GENERIC
WRITELN "#define __b2c__RIP3(x, y, z) __b2c__rip(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define RIP", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__RIP3, __b2c__RIP2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define RND random()" TO g_GENERIC
WRITELN "#define ROL(x) __b2c__rol(sizeof(__b2c__MEMTYPE), x)" TO g_GENERIC
WRITELN "#define ROR(x) __b2c__ror(sizeof(__b2c__MEMTYPE), x)" TO g_GENERIC
WRITELN "#define __b2c__ROTATE2(x, y) __b2c__rotate(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__ROTATE3(x, y, z) __b2c__rotate(x, y, z)" TO g_GENERIC
WRITELN "#define ROTATE", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__ROTATE3, __b2c__ROTATE2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define ROUND(x) lrint((double)x)" TO g_GENERIC
WRITELN "#define ROWS __b2c__screen(1)" TO g_GENERIC
WRITELN "#define __b2c__RUN1(x) __b2c__exec(1, __LINE__, __FILE__, x, NULL, 0)" TO g_GENERIC
WRITELN "#define __b2c__RUN2(x, y) __b2c__exec(1, __LINE__, __FILE__, x, y, 0)" TO g_GENERIC
WRITELN "#define __b2c__RUN3(x, y, z) __b2c__exec(1, __LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define RUN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__RUN3, __b2c__RUN2, __b2c__RUN1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__SEARCH2(x, y) __b2c__search(__LINE__, __FILE__, x, y, -1)" TO g_GENERIC
WRITELN "#define __b2c__SEARCH3(x, y, z) __b2c__search(__LINE__, __FILE__, x, y, z)" TO g_GENERIC
WRITELN "#define SEARCH(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__SEARCH3, __b2c__SEARCH2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define SECOND(x) __b2c__time(x, 6)" TO g_GENERIC
WRITELN "#define SETENVIRON(x, y) if((x) != NULL && (y) != NULL) setenv(x, y, 1)" TO g_GENERIC
WRITELN "#define SGN(x) ((x) == 0 ? 0 : ((x) < 0 ? -1 : 1))" TO g_GENERIC
WRITELN "#define SIN(x) sin((double)x)" TO g_GENERIC
WRITELN "#define SIZEOF(x) sizeof(x)" TO g_GENERIC
WRITELN "#define __b2c__SORT1(x) __b2c__sort(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__SORT2(x, y) __b2c__sort(x, y)" TO g_GENERIC
WRITELN "#define SORT", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__SORT2, __b2c__SORT1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define SPC", g_STRINGSIGN$, "(x) ((x) >= 0 ? __b2c__spc(x) : EmptyString)" TO g_GENERIC
WRITELN "#define SQR(x) sqrt((double)(x))" TO g_GENERIC
WRITELN "#define STR", g_STRINGSIGN$, "(x) __b2c__str(x)" TO g_GENERIC
WRITELN "#define STRING char*" TO g_GENERIC
WRITELN "#define SUM(x,...) __b2c__sum(", g_OPTION_BASE, ", x, __VA_ARGS__, LONG_MAX)" TO g_GENERIC
WRITELN "#define SUMF(x,...) __b2c__sumf(", g_OPTION_BASE, ", x, __VA_ARGS__, DBL_MAX)" TO g_GENERIC
WRITELN "#define SYSTEM(x) do {if (x != NULL) {RETVAL = system(x); if(WIFEXITED(RETVAL)) RETVAL = WEXITSTATUS(RETVAL);} else RETVAL=0;} while(0)" TO g_GENERIC
WRITELN "#define TAB", g_STRINGSIGN$, "(x) ((x) >= 0 ? __b2c__tab(x) : EmptyString)" TO g_GENERIC
WRITELN "#define __b2c__TAIL2(x, y) __b2c__tail(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__TAIL3(x, y, z) __b2c__tail(x, y, z)" TO g_GENERIC
WRITELN "#define TAIL", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__TAIL3, __b2c__TAIL2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__TALLY2(x, y) __b2c__tally(x, y, -1)" TO g_GENERIC
WRITELN "#define __b2c__TALLY3(x, y, z) __b2c__tally(x, y, z)" TO g_GENERIC
WRITELN "#define TALLY(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__TALLY3, __b2c__TALLY2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define TAN(x) tan((double)x)" TO g_GENERIC
WRITELN "#define TELL(x) ftell(x)" TO g_GENERIC
WRITELN "#define TIMER __b2c__timer(0)" TO g_GENERIC
WRITELN "#define TIMEVALUE(x,y,z,a,b,c) __b2c__epoch(x,y,z,a,b,c)" TO g_GENERIC
WRITELN "#define TOASCII", g_STRINGSIGN$, "(x) __b2c__toascii(x)" TO g_GENERIC
WRITELN "#define __b2c__TOKEN2(x, y) __b2c__token(x, y, NULL)" TO g_GENERIC
WRITELN "#define __b2c__TOKEN3(x, y, z) __b2c__token(x, y, z)" TO g_GENERIC
WRITELN "#define TOKEN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT3(__VA_ARGS__, __b2c__TOKEN3, __b2c__TOKEN2)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define TRUE 1" TO g_GENERIC
WRITELN "#define UCASE", g_STRINGSIGN$, "(x) __b2c__ucase(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define UCS(x) (unsigned int)__b2c__utf8toasc(x)" TO g_GENERIC
WRITELN "#define UNESCAPE", g_STRINGSIGN$, "(x) __b2c__unescape(__LINE__, __FILE__, x)" TO g_GENERIC
WRITELN "#define __b2c__UNFLATTEN1(x) __b2c__unflatten(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__UNFLATTEN2(x, y) __b2c__unflatten(x, y)" TO g_GENERIC
WRITELN "#define UNFLATTEN", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__UNFLATTEN2, __b2c__UNFLATTEN1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define __b2c__UNIQ1(x) __b2c__uniq(x, NULL)" TO g_GENERIC
WRITELN "#define __b2c__UNIQ2(x, y) __b2c__uniq(x, y)" TO g_GENERIC
WRITELN "#define UNIQ", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT2(__VA_ARGS__, __b2c__UNIQ2, __b2c__UNIQ1)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define VAL(x) ((x) != NULL ? atof(x) : 0)" TO g_GENERIC
WRITELN "#define WAIT(x, y) __b2c__netpeek(__LINE__, __FILE__, (uintptr_t)x, y)" TO g_GENERIC
WRITELN "#define __b2c__WALK4(x, y, z, q) __b2c__walk(__LINE__, __FILE__, x, y, z, q, NULL)" TO g_GENERIC
WRITELN "#define __b2c__WALK5(x, y, z, q, f) __b2c__walk(__LINE__, __FILE__, x, y, z, q, f)" TO g_GENERIC
WRITELN "#define WALK", g_STRINGSIGN$, "(...) __b2c__FUNCSELECT5(__VA_ARGS__, __b2c__WALK5, __b2c__WALK4)(__VA_ARGS__)" TO g_GENERIC
WRITELN "#define WEEK(x) __b2c__time(x, 7)" TO g_GENERIC
WRITELN "#define WEEKDAY", g_STRINGSIGN$, "(x) __b2c__datename(x, 1)" TO g_GENERIC
WRITELN "#define YEAR(x) __b2c__time(x, 3)" TO g_GENERIC
WRITELN "#define __b2c__cacerts NULL" TO g_GENERIC
WRITELN "#define __b2c__capeer 0" TO g_GENERIC
WRITELN "#define __b2c__caprivate NULL" TO g_GENERIC
WRITELN "#define __b2c__caserver NULL" TO g_GENERIC

CLOSE FILE g_GENERIC, g_CFILE, FLOATARRAYFILE, STRINGARRAYFILE

' Check presence of lex
IF LEN(EXEC$("which flex 2>/dev/null")) THEN
	g_LEX$ = "flex"
ELIF LEN(EXEC$("which lex 2>/dev/null")) THEN
	g_LEX$ = "lex"
ELSE
	PRINT "WARNING: neither 'lex' nor 'flex' was found on this system!"
	PRINT "Generated binary cannot be optimized."
ENDIF

' Create the lexer
IF LEN(g_LEX$) THEN
	' Create lexer file to see which functions are needed, so the resulting binary can be optimized
	OPEN g_BACONLEXER$ FOR WRITING AS g_BACONLEXER
	WRITELN "%{" TO g_BACONLEXER
	WRITELN "#include <stdio.h>" TO g_BACONLEXER
	WRITELN "%}" TO g_BACONLEXER
	WRITELN "%x text escaped comment multi" TO g_BACONLEXER
	WRITELN "WS [ \\n\\r\\t]+" TO g_BACONLEXER
	WRITELN "%%" TO g_BACONLEXER
	WRITELN "\"ALARM\"{WS}       printf(\"alarm \");" TO g_BACONLEXER
	WRITELN "\"ALIGN$(\"         printf(\"align delimengine \");" TO g_BACONLEXER
	WRITELN "\"AMOUNT(\"         printf(\"amount delimengine \");" TO g_BACONLEXER
	WRITELN "\"APPEND\"{WS}      printf(\"save concat \");" TO g_BACONLEXER
	WRITELN "\"APPEND$(\"        printf(\"append delimengine \");" TO g_BACONLEXER
	WRITELN "\"ASSOC\"{WS}       printf(\"hash sortstr sortnr \");" TO g_BACONLEXER
	WRITELN "\"B64DEC$(\"        printf(\"base64 \");" TO g_BACONLEXER
	WRITELN "\"B64ENC$(\"        printf(\"base64 \");" TO g_BACONLEXER
	WRITELN "\"BASENAME$(\"      printf(\"dirname \");" TO g_BACONLEXER
	WRITELN "\"BIT(\"            printf(\"binary \");" TO g_BACONLEXER
	WRITELN "\"BIN$(\"           printf(\"binary \");" TO g_BACONLEXER
	WRITELN "\"BLOAD(\"          printf(\"load \");" TO g_BACONLEXER
	WRITELN "\"CA$(\"            printf(\"cipher \");" TO g_BACONLEXER
	WRITELN "\"CHANGE$(\"        printf(\"change delimengine \");" TO g_BACONLEXER
	WRITELN "\"CHOP$(\"          printf(\"chop \");" TO g_BACONLEXER
	WRITELN "\"CHR$(\"           printf(\"chrstr \");" TO g_BACONLEXER
	WRITELN "\"CIPHER$(\"        printf(\"cipher \");" TO g_BACONLEXER
	WRITELN "\"CMDLINE(\"        printf(\"cmdline \");" TO g_BACONLEXER
	WRITELN "\"CN$(\"            printf(\"cipher \");" TO g_BACONLEXER
	WRITELN "\"COIL$(\"          printf(\"append delimengine \");" TO g_BACONLEXER
	WRITELN "\"COLLAPSE$(\"      printf(\"collapsefunc delimengine \");" TO g_BACONLEXER
	WRITELN "\"COLLECT\"{WS}     printf(\"collect \");" TO g_BACONLEXER
	WRITELN "\"COLUMNS\"         printf(\"screen \");" TO g_BACONLEXER
	WRITELN "\"&\"               printf(\"concat \");" TO g_BACONLEXER
	WRITELN "\"CONCAT$(\"        printf(\"concat \");" TO g_BACONLEXER
	WRITELN "\"COPY\"{WS}        printf(\"copy \");" TO g_BACONLEXER
	WRITELN "\"COUNT(\"          printf(\"count chrstr \");" TO g_BACONLEXER
	WRITELN "\"CURDIR$\"         printf(\"curdir \");" TO g_BACONLEXER
	WRITELN "\"CUT$(\"           printf(\"cut delimengine \");" TO g_BACONLEXER
	WRITELN "\"DAY(\"            printf(\"chrono \");" TO g_BACONLEXER
	WRITELN "\"DEC(\"            printf(\"dec \");" TO g_BACONLEXER
	WRITELN "\"DEL$(\"           printf(\"delstr delimengine \");" TO g_BACONLEXER
	WRITELN "\"DELIM$(\"         printf(\"delimstr delimengine \");" TO g_BACONLEXER
	WRITELN "\"DIRNAME$(\"       printf(\"dirname \");" TO g_BACONLEXER
	WRITELN "\"ESCAPE$(\"        printf(\"doescape chrstr \");" TO g_BACONLEXER
	WRITELN "\"EVAL(\"           printf(\"eval \");" TO g_BACONLEXER
	WRITELN "\"EXCHANGE$(\"      printf(\"exchange delimengine \");" TO g_BACONLEXER
	WRITELN "\"EXEC$(\"          printf(\"exec \");" TO g_BACONLEXER
	WRITELN "\"EXPLODE$(\"       printf(\"explode delimengine \");" TO g_BACONLEXER
	WRITELN "\"EXTRACT$(\"       printf(\"extract \");" TO g_BACONLEXER
	WRITELN "\"FILELEN(\"        printf(\"filelen \");" TO g_BACONLEXER
	WRITELN "\"FILETIME(\"       printf(\"filetime \");" TO g_BACONLEXER
	WRITELN "\"FILETYPE(\"       printf(\"filetype \");" TO g_BACONLEXER
	WRITELN "\"FILL$(\"          printf(\"fill \");" TO g_BACONLEXER
	WRITELN "\"FIND(\"           printf(\"find \");" TO g_BACONLEXER
	WRITELN "\"FIRST$(\"         printf(\"first delimengine \");" TO g_BACONLEXER
	WRITELN "\"FLATTEN$(\"       printf(\"flatten \");" TO g_BACONLEXER
	WRITELN "\"FOR\"{WS}         printf(\"for delimengine \");" TO g_BACONLEXER
	WRITELN "\"GETENVIRON$(\"    printf(\"getenviron \");" TO g_BACONLEXER
	WRITELN "\"GETFILE\"{WS}     printf(\"getfile \");" TO g_BACONLEXER
	WRITELN "\"GETKEY\"          printf(\"getkey \");" TO g_BACONLEXER
	WRITELN "\"GETLINE\"{WS}     printf(\"getline \");" TO g_BACONLEXER
	WRITELN "\"GETPEER$(\"       printf(\"getpeer \");" TO g_BACONLEXER
	WRITELN "\"GETX\"            printf(\"getxy \");" TO g_BACONLEXER
	WRITELN "\"GETY\"            printf(\"getxy \");" TO g_BACONLEXER
	WRITELN "\"HASDELIM(\"       printf(\"hasdelim delimengine \");" TO g_BACONLEXER
	WRITELN "\"HASH(\"           printf(\"hash sortstr sortnr \");" TO g_BACONLEXER
	WRITELN "\"HEAD$(\"          printf(\"head delimengine \");" TO g_BACONLEXER
	WRITELN "\"HEX$(\"           printf(\"hex \");" TO g_BACONLEXER
	WRITELN "\"HOST$(\"          printf(\"host \");" TO g_BACONLEXER
	WRITELN "\"HOSTNAME$\"       printf(\"hostname \");" TO g_BACONLEXER
	WRITELN "\"HOUR(\"           printf(\"chrono \");" TO g_BACONLEXER
	WRITELN "\"INBETWEEN$(\"     printf(\"between delimengine \");" TO g_BACONLEXER
	WRITELN "\"INDEX(\"          printf(\"index sortnr sortstr \");" TO g_BACONLEXER
	WRITELN "\"INPUT\"{WS}       printf(\"input \");" TO g_BACONLEXER
	WRITELN "\"INSERT$(\"        printf(\"insert \");" TO g_BACONLEXER
	WRITELN "\"INSTR(\"          printf(\"instring \");" TO g_BACONLEXER
	WRITELN "\"INSTRREV(\"       printf(\"instrrev \");" TO g_BACONLEXER
	WRITELN "\"ISASCII(\"        printf(\"chrstr \");" TO g_BACONLEXER
	WRITELN "\"ISTOKEN(\"        printf(\"istok delimengine \");" TO g_BACONLEXER
	WRITELN "\"ISUTF8(\"         printf(\"chrstr \");" TO g_BACONLEXER
	WRITELN "\"JOIN\"{WS}        printf(\"join \");" TO g_BACONLEXER
	WRITELN "\"LAST$(\"          printf(\"last delimengine \");" TO g_BACONLEXER
	WRITELN "\"LCASE$(\"         printf(\"lcase \");" TO g_BACONLEXER
	WRITELN "\"LEFT$(\"          printf(\"left \");" TO g_BACONLEXER
	WRITELN "\"LOAD$(\"          printf(\"load \");" TO g_BACONLEXER
	WRITELN "\"LOOKUP\"{WS}      printf(\"lookup hash sortnr sortstr \");" TO g_BACONLEXER
	WRITELN "\"LOOP$(\"          printf(\"concat \");" TO g_BACONLEXER
	WRITELN "\"MAKEDIR\"{WS}     printf(\"makedir delimengine \");" TO g_BACONLEXER
	WRITELN "\"MATCH(\"          printf(\"match delimengine \");" TO g_BACONLEXER
	WRITELN "\"MERGE$(\"         printf(\"merge delimengine \");" TO g_BACONLEXER
	WRITELN "\"MID$(\"           printf(\"mid \");" TO g_BACONLEXER
	WRITELN "\"MINUTE(\"         printf(\"chrono \");" TO g_BACONLEXER
	WRITELN "\"MONTH(\"          printf(\"chrono \");" TO g_BACONLEXER
	WRITELN "\"MONTH$(\"         printf(\"datename \");" TO g_BACONLEXER
	WRITELN "\"NETWORK\"{WS}     printf(\"network delimengine \");" TO g_BACONLEXER
	WRITELN "\"OBTAIN$(\"        printf(\"obtain hash sortnr sortstr \");" TO g_BACONLEXER
	WRITELN "\"OS$\"             printf(\"os \");" TO g_BACONLEXER
	WRITELN "\"OUTBETWEEN$(\"    printf(\"between delimengine \");" TO g_BACONLEXER
	WRITELN "\"PARSE\"{WS}       printf(\"parse delimengine \");" TO g_BACONLEXER
	WRITELN "\"PEEK(\"           printf(\"peek \");" TO g_BACONLEXER
	WRITELN "\"PROPER$(\"        printf(\"proper delimengine \");" TO g_BACONLEXER
	WRITELN "\"READLN\"{WS}      printf(\"readln \");" TO g_BACONLEXER
	WRITELN "\"REALPATH$(\"      printf(\"dirname \");" TO g_BACONLEXER
	WRITELN "\"RECURSIVE\"{WS}   printf(\"recursive \");" TO g_BACONLEXER
	WRITELN "\"REGEX(\"          printf(\"regex \");" TO g_BACONLEXER
	WRITELN "\"REPLACE$(\"       printf(\"replace \");" TO g_BACONLEXER
	WRITELN "\"RETURN\"{WS}      printf(\"return \");" TO g_BACONLEXER
	WRITELN "\"REV$(\"           printf(\"revstr delimengine \");" TO g_BACONLEXER
	WRITELN "\"REVERSE$(\"       printf(\"reverse \");" TO g_BACONLEXER
	WRITELN "\"RIGHT$(\"         printf(\"right \");" TO g_BACONLEXER
	WRITELN "\"RIP$(\"           printf(\"rip \");" TO g_BACONLEXER
	WRITELN "\"ROL(\"            printf(\"binary \");" TO g_BACONLEXER
	WRITELN "\"ROR(\"            printf(\"binary \");" TO g_BACONLEXER
	WRITELN "\"ROTATE$(\"        printf(\"rotate delimengine \");" TO g_BACONLEXER
	WRITELN "\"ROWS\"            printf(\"screen \");" TO g_BACONLEXER
	WRITELN "\"RUN$(\"           printf(\"exec \");" TO g_BACONLEXER
	WRITELN "\"SAVE\"{WS}        printf(\"save \");" TO g_BACONLEXER
	WRITELN "\"SEARCH(\"         printf(\"search \");" TO g_BACONLEXER
	WRITELN "\"SECOND(\"         printf(\"chrono \");" TO g_BACONLEXER
	WRITELN "\"SERVER\"{WS}      printf(\"server delimengine \");" TO g_BACONLEXER
	WRITELN "\"SETSERIAL\"{WS}   printf(\"setserial \");" TO g_BACONLEXER
	WRITELN "\"SIGNAL\"{WS}      printf(\"signal \");" TO g_BACONLEXER
	WRITELN "\"SORT\"{WS}        printf(\"sortnr sortstr \");" TO g_BACONLEXER
	WRITELN "\"SORT$(\"          printf(\"sortdelim sortstr delimengine \");" TO g_BACONLEXER
	WRITELN "\"SPC$(\"           printf(\"spc \");" TO g_BACONLEXER
	WRITELN "\"SPLIT\"{WS}       printf(\"split delimengine \");" TO g_BACONLEXER
	WRITELN "\"SUM(\"            printf(\"sum \");" TO g_BACONLEXER
	WRITELN "\"SUMF(\"           printf(\"sum \");" TO g_BACONLEXER
	WRITELN "\"TAB$(\"           printf(\"tab \");" TO g_BACONLEXER
	WRITELN "\"TAIL$(\"          printf(\"tail delimengine \");" TO g_BACONLEXER
	WRITELN "\"TALLY(\"          printf(\"tally \");" TO g_BACONLEXER
	WRITELN "\"TIMER\"           printf(\"timer \");" TO g_BACONLEXER
	WRITELN "\"TIMEVALUE(\"      printf(\"epoch \");" TO g_BACONLEXER
	WRITELN "\"TOASCII$(\"       printf(\"chrstr \");" TO g_BACONLEXER
	WRITELN "\"TOKEN$(\"         printf(\"token delimengine \");" TO g_BACONLEXER
	WRITELN "\"TRACE\"{WS}       printf(\"getkey \");" TO g_BACONLEXER
	WRITELN "\"TREE\"{WS}        printf(\"tree sortnr sortstr \");" TO g_BACONLEXER
	WRITELN "\"UCASE$(\"         printf(\"ucase \");" TO g_BACONLEXER
	WRITELN "\"UCS(\"            printf(\"chrstr \");" TO g_BACONLEXER
	WRITELN "\"UNESCAPE$(\"      printf(\"unescape \");" TO g_BACONLEXER
	WRITELN "\"UNFLATTEN$(\"     printf(\"flatten \");" TO g_BACONLEXER
	WRITELN "\"UNIQ$(\"          printf(\"uniq obtain delimengine hash sortnr sortstr \");" TO g_BACONLEXER
	WRITELN "\"UTF8$(\"          printf(\"chrstr \");" TO g_BACONLEXER
	WRITELN "\"WAIT(\"           printf(\"wait \");" TO g_BACONLEXER
	WRITELN "\"WALK$(\"          printf(\"walk \");" TO g_BACONLEXER
	WRITELN "\"WEEK(\"           printf(\"chrono \");" TO g_BACONLEXER
	WRITELN "\"WEEKDAY$(\"       printf(\"datename \");" TO g_BACONLEXER
	WRITELN "\"YEAR(\"           printf(\"chrono \");" TO g_BACONLEXER
	WRITELN "\\\"                BEGIN(text);" TO g_BACONLEXER
	WRITELN "<text>\\\\          BEGIN(escaped);" TO g_BACONLEXER
	WRITELN "<text>\\\"          BEGIN(INITIAL);" TO g_BACONLEXER
	WRITELN "<text>.             /* Do nothing */" TO g_BACONLEXER
	WRITELN "<escaped>\\n\\\"    BEGIN(INITIAL);" TO g_BACONLEXER
	WRITELN "<escaped>\\n        /* Do nothing */" TO g_BACONLEXER
	WRITELN "<escaped>.          BEGIN(text);" TO g_BACONLEXER
	WRITELN "\\\'                BEGIN(comment);" TO g_BACONLEXER
	WRITELN "<comment>\\n        BEGIN(INITIAL);" TO g_BACONLEXER
	WRITELN "<comment>.          /* Do nothing */" TO g_BACONLEXER
	WRITELN "\"/*\"              BEGIN(multi);" TO g_BACONLEXER
	WRITELN "<multi>[^*]*        /* Eat anything that's not a '*' */" TO g_BACONLEXER
	WRITELN "<multi>\"*\"+[^*/]* /* Eat up '*'s not followed by '/' */" TO g_BACONLEXER
	WRITELN "<multi>\"*\"+\"/\"  BEGIN(INITIAL);" TO g_BACONLEXER
	WRITELN "{WS}                /* Skip whitespace */" TO g_BACONLEXER
	WRITELN ".                   /* Skip anything else */" TO g_BACONLEXER
	WRITELN "<<EOF>>             yyterminate();" TO g_BACONLEXER
	WRITELN "%%" TO g_BACONLEXER
	WRITELN "int main(int argc, char *argv[]) { printf(\"argument error malloc memcheck minmax str timer utf8 \"); yylex(); return(0); } int yywrap(void) { return(1); }" TO g_BACONLEXER
	CLOSE FILE g_BACONLEXER

	PRINT "Creating lexical analyzer... ";
	SYSTEM g_LEX$ & " -o " & g_BACONLEXER$ & ".c " & g_BACONLEXER$
	SYSTEM g_CCNAME$ & " " & g_BACONLEXER$ & ".c -o " & g_BACONLEXER$ & ".exe"
	PRINT "done."

	' Create list of required functions
	total$ = EXEC$(g_BACONLEXER$ & ".exe", LOAD$(FEED$))
	FOR tmpfile$ IN g_TMP_FILES$
		IF REGEX(tmpfile$, ".bac$") THEN total$ = total$ & EXEC$(g_BACONLEXER$ & ".exe", LOAD$(tmpfile$))
	NEXT
	IF g_DEBUG = 1 THEN PRINT "Analyzing dependencies... ", SORT$(UNIQ$(total$))
	nolex = FALSE
	g_TMP_FILES$ = g_TMP_FILES$ & " " & g_GENERIC$ & " " & g_FUNCTIONS$ & " " & g_BACONLEXER$ & " " & g_BACONLEXER$ & ".c " & g_BACONLEXER$ & ".exe"
ELSE
	nolex = TRUE
	g_TMP_FILES$ = g_TMP_FILES$ & " " & g_GENERIC$ & " " & g_FUNCTIONS$
ENDIF

' Generate functions
OPEN g_FUNCTIONS$ FOR WRITING AS g_FUNCTIONS
WRITELN "/* Created with BaCon ", g_VERSION$, " - (c) Peter van Eerten - MIT License */" TO g_FUNCTIONS
IF TALLY(total$, "base64") OR nolex THEN
	WRITELN "/* Portions of this code based on Bob Trower's C implementation at http://base64.sourceforge.net - MIT licensed */ static const char cd64[]=\"|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\\\]^_`abcdefghijklmnopq\";" TO g_FUNCTIONS
	WRITELN "static const char cb64[]=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"; static void __b2c__encodeblock( unsigned char *in, unsigned char *out, int len)" TO g_FUNCTIONS
	WRITELN "{ out[0] = (unsigned char) cb64[ (int)(in[0] >> 2) ]; out[1] = (unsigned char) cb64[ (int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) ];" TO g_FUNCTIONS
	WRITELN "out[2] = (unsigned char) (len > 1 ? cb64[ (int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) ] : '='); out[3] = (unsigned char) (len > 2 ? cb64[ (int)(in[2] & 0x3f) ] : '='); }" TO g_FUNCTIONS
	WRITELN "char * __b2c__b64enc (char* src, int len) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; unsigned char in[4], out[4]; int i, j, cur = 0, posit = 0; if (src == NULL) { return (EmptyString); }" TO g_FUNCTIONS
	WRITELN "if (len == 0) { len = __b2c__len (src); } if (len == 0) { return (EmptyString); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], ((len + 2) / 3) * 4 + 1);" TO g_FUNCTIONS
	WRITELN "while( cur < len ){ for( i = 0; i < 3 && (cur + i < len); i++ ){ in[i] = (unsigned char) src[cur+i]; } in[i] = 0; cur += i; if( i > 0 ) { __b2c__encodeblock( in, out, i );" TO g_FUNCTIONS
	WRITELN "for( j = 0; j < 4; j++ ) { buf[idx][posit+j] = out[j]; } posit += 4; } } buf[idx][posit] = '\\0'; __b2c__SETLEN (buf[idx], posit); return(char*)(buf[idx]); }" TO g_FUNCTIONS
	WRITELN "static void __b2c__decodeblock(unsigned char in[4], unsigned char out[3]) { out[0] = (unsigned char ) (in[0] << 2 | in[1] >> 4); out[1] = (unsigned char)(in[1] << 4 | in[2] >> 2);" TO g_FUNCTIONS
	WRITELN "out[2] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__b64dec(int l, char *k, char *src) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; unsigned char in[4], out[3], v; int i = 0, stlen, dec_len, len, cur = 0, posit = 0; if(src == NULL){ return (EmptyString); }" TO g_FUNCTIONS
	WRITELN "stlen = __b2c__len (src); if (stlen == 0) { return (EmptyString); } if(stlen % 4) { ERROR = 5; RUNTIMEFERR (\"B64DEC$\", ERROR, k, l); } dec_len = 3*stlen/4; while(src[stlen+i-1] == 61) { dec_len--; i--; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], dec_len + 4); while(cur < stlen){ for (len = 0, i = 0; i < 4 && (cur < stlen); i++) { v = 0; while (cur < stlen && v == 0){ v = (unsigned char) src[cur]; cur++; v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);" TO g_FUNCTIONS
	WRITELN "if (v) {v = (unsigned char) ((v == '$') ? 0 : v - 61);} } if(cur <= stlen){ len++; if (v) { in[i] = (unsigned char)(v - 1); } else { in[i] = 0; } } } if(len){ __b2c__decodeblock(in, out);" TO g_FUNCTIONS
	WRITELN "for(i = 0; i < len - 1; i++) { buf[idx][posit + i] = out[i]; } buf[idx][posit + i] = '\\0'; posit += len - 1; } } __b2c__SETLEN(buf[idx], dec_len); return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "binary") OR nolex THEN
	WRITELN "unsigned long __b2c__bit(long x) { return(x ? 2<<(x-1) : 1); } unsigned long __b2c__rol(int type, long x)" TO g_FUNCTIONS
	WRITELN "{ return((x)&lrint(pow(2, type*8-1)) ? (((x)<<1)|1)&lrint(pow(2, type*8)-1) : ((x)<<1)&lrint(pow(2, type*8)-1)); }" TO g_FUNCTIONS
	WRITELN "unsigned long __b2c__ror(int type, long x) { return((x)&1 ? (((x)>>1)&lrint(pow(2, type*8)-1))|lrint(pow(2, type*8-1)) : ((x)>>1)&lrint(pow(2, type*8)-1)); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__bin(int type, long x) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long i; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], type*8+1); for(i = 0; i<type*8; i++) { if(x&1) { buf[idx][type*8-1-i] = 49; } else { buf[idx][type*8-1-i] = 48; }" TO g_FUNCTIONS
	WRITELN "x = x>>1; } buf[idx][type*8] = '\\0'; __b2c__SETLEN(buf[idx], type*8); return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "chop") OR nolex THEN
	WRITELN "char *__b2c__chop (char *source, char *string, int location) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char *tmp; long length; if (source == NULL || *source == '\\0') { return (source); } if (string == NULL) { string = (char *) __b2c__chop_default; }" TO g_FUNCTIONS
	WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } length = __b2c__len(string); if (location == 0 || location == 1) { while (*source != '\\0') { if(memchr(string, *source, length)) { source++; } else { break; } } if (*source == '\\0'){ return (EmptyString); } } tmp = source + strlen(source) - 1;" TO g_FUNCTIONS
	WRITELN "if(location == 0 || location == 2) { while (tmp >= source && *tmp != '\\0') { if(memchr(string, *tmp, length)) { tmp--; } else { break; } } } tmp++; buf[idx] = (char*)__b2c_str_realloc(buf[idx], tmp-source+1); memmove(buf[idx], source, tmp - source);" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], tmp - source); buf[idx][tmp - source] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "chrstr") OR nolex THEN
	WRITELN "char *__b2c__asc2char (int i) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; int len; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], 2); len = snprintf(buf[idx], 2, \"%c\", i); __b2c__SETLEN(buf[idx], len); return(char*)(buf[idx]); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__asc2utf8 (int i) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; int len; char buffer[5]; len = __b2c_utf8_conv(i, buffer); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+1); memcpy(buf[idx], buffer, len); __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
	WRITELN "unsigned int __b2c__utf8toasc(char* ptr) { unsigned int result = 0; if((*ptr&0xF0)==0xF0) { result = (*ptr&0x07)<<2; ptr++; result = result | ((*ptr&0x30)>>4); result = result << 8; result = result | ((*ptr&0x0F)<<4);" TO g_FUNCTIONS
	WRITELN "ptr++; result = result | ((*ptr&0x3C)>>2); result = result << 8; result = result | ((*ptr&0x03)<<6); ptr++; result = result | (*ptr&0x3F); } else if((*ptr&0xE0)==0xE0) { result = (*ptr&0x0F)<<4; ptr++;" TO g_FUNCTIONS
	WRITELN "result = result | ((*ptr&0x3C)>>2); result = result << 8; result = result | ((*ptr&0x03)<<6); ptr++; result = result | (*ptr&0x3F); } else if((*ptr&0xC0)==0xC0) { result = (*ptr&0x1C)>>2; result = result << 8;" TO g_FUNCTIONS
	WRITELN "result = result | ((*ptr&0x03)<<6); ptr++; result = result | (*ptr&0x3F); } else if((*ptr&0x80) == 0) { result = (*ptr&0x7F); } return (result); }" TO g_FUNCTIONS
	WRITELN "unsigned char __b2c__isascii(const char *ptr) { long x; for(x=0; *(ptr+x); x++) { if(*(ptr+x)&128) return(0); } return(1); }" TO g_FUNCTIONS
	WRITELN "unsigned char __b2c__isutf8(const char *ptr) { int result = 1; if (ptr == NULL) { return (0); } while (*ptr) { if ((*ptr & 0xF0) == 0xF0)" TO g_FUNCTIONS
	WRITELN "{ if ((*(ptr + 1) & 0xC0) != 0x80 || (*(ptr + 2) & 0xc0) != 0x80 || (*(ptr + 3) & 0xc0) != 0x80 ) { result = 0; break; } ptr += 4; } else if ((*ptr & 0xE0) == 0xE0)" TO g_FUNCTIONS
	WRITELN "{ if ((*(ptr + 1) & 0xc0) != 0x80 || (*(ptr + 2) & 0xc0) != 0x80 ) { result = 0; break; } ptr += 3; } else if ((*ptr & 0xC0) == 0xC0) { if ((*(ptr + 1) & 0xc0) != 0x80 )" TO g_FUNCTIONS
	WRITELN "{ result = 0; break; } ptr += 2; } else if ((*ptr & 0x80) == 0) { ptr++; } else { result = 0; break; } } return (result); }" TO g_FUNCTIONS
	WRITELN "char* __b2c__toascii(char *ptr) { int len, x; len = __b2c__len(ptr); for(x=0; x < len; x++) { *(ptr+x) = *(ptr+x)&0x7f; } return (ptr); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "cmdline") OR nolex THEN
	WRITELN "int __b2c__getopt(int argc, char **argv, char* str){int opt; extern char *optarg; extern int optind, opterr; opterr = 0; opt = getopt(argc, argv, str); __b2c__STRFREE(ARGUMENT", g_STRINGSIGN$, ");" TO g_FUNCTIONS
	WRITELN "if(opt != -1) { ARGUMENT", g_STRINGSIGN$, " = __b2c__strdup(optarg); } else { ARGUMENT", g_STRINGSIGN$, " = argv[optind]; } return(opt);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "concat") OR nolex THEN
	WRITELN "char *__b2c__concat (int n, ...) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long length = 0, cnew; char *next; va_list ap; if(n == 0) { return(EmptyString); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "va_start (ap, n); while(n) { next = va_arg(ap, char*); if(next) { cnew = __b2c__len (next); buf[idx] = (char*)__b2c_str_realloc(buf[idx], length + cnew + 1); memmove(buf[idx] + length, next, cnew);" TO g_FUNCTIONS
	WRITELN "length += cnew; } n--; } va_end(ap); __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; return((char*)buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "count") OR nolex THEN
	WRITELN "long __b2c__count (int l, char *k, char *x, unsigned int y) { long i, z = 0; if (__b2c__option_utf8) { while (*x) { if (__b2c__utf8toasc (x) == y) { z++; } if ((*x & 0xF0) == 0xF0) { x += 4; }" TO g_FUNCTIONS
	WRITELN "else if ((*x & 0xE0) == 0xE0) { x += 3; } else if ((*x & 0xC0) == 0xC0) { x += 2; } else if ((*x & 0x80) == 0) { x++; } else { ERROR = 38; RUNTIMEFERR (\"COUNT\", ERROR, k, l); } } } else " TO g_FUNCTIONS
	WRITELN "{ for (i = 0; x[i] != '\\0'; i++) { if (x[i] == y) { z++; } } } return z; }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "curdir") OR nolex THEN
	WRITELN "char *__b2c__curdir (void) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], ", g_BUFFER_SIZE, ");" TO g_FUNCTIONS
	WRITELN "buf[idx] = getcwd(buf[idx], ", g_BUFFER_SIZE, "); __b2c__SETLEN(buf[idx], strlen(buf[idx])); buf[idx][", g_BUFFER_SIZE, "-1] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "datename") OR nolex THEN
	WRITELN "char* __b2c__datename(time_t now, int which) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; struct tm *ts; int len = 0; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], ", g_MAX_DIGITS, "); ts = localtime (&now); switch (which) { case 1: len = strftime(buf[idx], ", g_MAX_DIGITS, ", \"%A\", ts); break;" TO g_FUNCTIONS
	WRITELN "case 2: len = strftime(buf[idx], ", g_MAX_DIGITS, ", \"%B\", ts); break; } __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "dec") OR nolex THEN
	WRITELN "uint64_t __b2c__hex2dec (int l, char *k, char *h, int flag) { uint64_t j=0; char *status = NULL; if(h == NULL) { return(0); } if(flag == 1) { flag = 2; } else if(flag > 36) {ERROR = 5; RUNTIMEFERR (\"DEC\", ERROR, k, l);}" TO g_FUNCTIONS
	WRITELN "if(flag == 0) { j = strtol(h, &status, 16); if(*status != '\\0' && __b2c__trap) { ERROR = 5; RUNTIMEFERR (\"DEC\", ERROR, k, l); } } else { j = strtol(h, &status, flag);" TO g_FUNCTIONS
	WRITELN "if(*status != '\\0') { ERROR = 5; RUNTIMEFERR (\"DEC\", ERROR, k, l); } } return(uint64_t)(j); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "dirname") OR nolex THEN
	WRITELN "#ifndef PATH_MAX" TO g_FUNCTIONS
	WRITELN "#define PATH_MAX 4096" TO g_FUNCTIONS
	WRITELN "#endif" TO g_FUNCTIONS
	WRITELN "char *__b2c__dirname(int l, char *k, int x, char *y, long arg) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long i; char *dup; if(y == NULL || __b2c__len(y) == 0){ return(EmptyString); }" TO g_FUNCTIONS
	WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], PATH_MAX*sizeof(char)); dup = __b2c__strdup(y); switch(x) {case 0: if ((realpath(y, buf[idx])) == NULL) { if (__b2c__trap) { ERROR = 26; RUNTIMEFERR(\"REALPATH$\", ERROR, k, l);}" TO g_FUNCTIONS
	WRITELN "else strncpy(buf[idx], \"Error getting real path\",", g_BUFFER_SIZE, "); } break; case 1: if(strncpy(buf[idx], basename(dup), PATH_MAX) == NULL) {if (__b2c__trap) { ERROR = 26; RUNTIMEFERR(\"BASENAME$\", ERROR, k, l); } else strncpy (buf[idx], \"Error getting basename\",", g_BUFFER_SIZE, ");}" TO g_FUNCTIONS
	WRITELN "break; case 2: if (strncpy(buf[idx], dirname(dup), PATH_MAX) == NULL) {if(__b2c__trap) { ERROR = 26; RUNTIMEFERR(\"DIRNAME$\", ERROR, k, l); } else strncpy(buf[idx], \"Error getting dirname\",", g_BUFFER_SIZE, "); " TO g_FUNCTIONS
	WRITELN "} break;} free(dup); __b2c__SETLEN(buf[idx], strlen(buf[idx])); buf[idx][PATH_MAX - 1] = '\\0'; if(arg && x==1){ for(i=__b2c__len(buf[idx]); i>=0; i--) { if(buf[idx][i] == 46) break; }" TO g_FUNCTIONS
	WRITELN "if(i >= 0){ if(arg == 1) {buf[idx][i] = '\\0'; __b2c__SETLEN(buf[idx], i);} if(arg == 2){ i++; memmove(buf[idx], buf[idx]+i, __b2c__len(buf[idx])-i+1);" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], __b2c__len(buf[idx])-i);} } else if(arg == 2) {buf[idx][0] = '\\0'; __b2c__SETLEN(buf[idx], 0);} } return(char*)(buf[idx]);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "epoch") OR nolex THEN
	WRITELN "unsigned long __b2c__epoch(int year, int month, int day, int hour, int minute, int second){struct tm tm; time_t t; tm.tm_year = year - 1900; tm.tm_mon = month - 1; tm.tm_mday = day;" TO g_FUNCTIONS
	WRITELN "tm.tm_hour = hour; tm.tm_min = minute; tm.tm_sec = second; tm.tm_isdst = -1; t = mktime(&tm); if (t == -1) return (0); return(long) t; }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "error") OR nolex THEN
	WRITELN "char *ERR", g_STRINGSIGN$, "(int nr){ static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long flen = 0, slen = 0; char *first = NULL, *second = NULL; switch (nr)" TO g_FUNCTIONS
	WRITELN "{ case 0: first = \"Success\"; break; case 1: first = \"Trying to access illegal memory: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 2: first = \"Error opening file: \"; second = strerror (errno); break; case 3: first = \"Could not open library.\"; break;" TO g_FUNCTIONS
	WRITELN "case 4: first = \"Symbol not found in library.\"; break; case 5: first = \"Wrong value: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 6: first = \"Unable to claim memory.\"; break; case 7: first = \"Unable to delete file: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 8: first = \"Could not open directory: \"; second = strerror(errno); break; case 9: first = \"Unable to rename file: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 10: first = \"NETWORK argument should contain colon with port number\"; break; case 11: first = \"Could not resolve hostname!\"; break;" TO g_FUNCTIONS
	WRITELN "case 12: first = \"Socket error: \"; second = strerror(errno); break; case 13: first = \"Unable to open address: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 14: first = \"Error reading from socket: \"; second = strerror(errno); break; case 15: first = \"Error sending to socket: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 16: first = \"Error checking socket: \"; second = strerror(errno); break; case 17: first = \"Unable to bind the specified socket address: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 18: first = \"Unable to listen to socket address: \"; second = strerror(errno); break; case 19: first = \"Cannot accept incoming connection: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 20: first = \"Unable to remove directory: \"; second = strerror(errno); break; case 21: first = \"Unable to create directory: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 22: first = \"Unable to change to directory: \"; second = strerror(errno); break; case 23: first = \"GETENVIRON argument does not exist as environment variable\"; break;" TO g_FUNCTIONS
	WRITELN "case 24: first = \"Unable to stat file: \"; second = strerror(errno); break; case 25: first = \"Search contains illegal string\"; break;" TO g_FUNCTIONS
	WRITELN "case 26: first = \"Cannot return name: \"; second = strerror(errno); break; case 27: first = \"Illegal regex expression\"; break;" TO g_FUNCTIONS
	WRITELN "case 28: first = \"Unable to create bidirectional pipes: \"; second = strerror(errno); break; case 29: first = \"Unable to fork process: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 30: first = \"Cannot read from pipe: \"; second = strerror(errno); break; case 31: first = \"Gosub nesting too deep!\"; break;" TO g_FUNCTIONS
	WRITELN "case 32: first = \"Could not open device: \"; second = strerror(errno); break; case 33: first = \"Error configuring serial port: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 34: first = \"Error accessing device: \"; second = strerror(errno); break; case 35: first = \"Error in INPUT: \"; second = strerror(errno); break;" TO g_FUNCTIONS
	WRITELN "case 36: first = \"Illegal value in SORT dimension!\"; break; case 37: first = \"Illegal option for SEARCH!\"; break;" TO g_FUNCTIONS
	WRITELN "case 38: first = \"Invalid UTF8 string!\"; break; case 39: first = \"Illegal EVAL expression!\"; break;" TO g_FUNCTIONS
	WRITELN "case 40: first = \"SSL file descriptor error!\"; break; case 41: first = \"Error loading certificate!\"; break;" TO g_FUNCTIONS
	WRITELN "case 42: first = \"Widget not found!\"; ERROR = 42; break; case 43: first = \"Unsupported array type!\"; break; };" TO g_FUNCTIONS
	WRITELN "if(first) { flen = strlen(first); } if(second) { slen = strlen(second); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], flen+slen+1);if(first)" TO g_FUNCTIONS
	WRITELN "{ memmove(buf[idx], first, flen); } if(second) { memmove(buf[idx]+flen, second, slen); } __b2c__SETLEN(buf[idx], flen+slen); buf[idx][flen+slen] = '\\0'; return((char*)buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "exec") OR nolex THEN
	WRITELN "static char ** __b2c__Get_Args (char *line) { char **ptr = NULL; char *arg; int in_string = 0, x = 0; arg = line; while (*line != '\\0') { switch (*line) { case 34: in_string = 1 - in_string; line++; break;" TO g_FUNCTIONS
	WRITELN "case 32: if (!in_string) { ptr = (char **) realloc (ptr, (x + 1) * sizeof (char *)); if(*arg == 34) arg++; if(*(line-1) == 34) line--; ptr[x] = __b2c__strndup(arg, line-arg); while (isspace (*line) && *line != '\\0'){ line++; } arg = line; x++; }" TO g_FUNCTIONS
	WRITELN "else {line++;} break; default: line++; } } ptr = (char **) realloc (ptr, (x + 2) * sizeof (char *)); if(*arg == 34) arg++; if(*(line-1) == 34) line--; ptr[x] = __b2c__strndup (arg, line - arg); ptr[x+1] = NULL; return (ptr); }" TO g_FUNCTIONS
	WRITELN "char * __b2c__exec(int t, int l, char *k, char *cmd, char *str, int out) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; int forking, length, dnull; ssize_t result = 0; int wpipe[2], rpipe[2]; char **args; char *ans = NULL;" TO g_FUNCTIONS
	WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], sizeof(char)); if (pipe (rpipe) < 0 || pipe (wpipe) < 0) { if (__b2c__trap) { ERROR = 29; RUNTIMEFERR(\"EXEC$\", ERROR, k, l); } } if ((forking = fork ()) < 0) { if (__b2c__trap) { ERROR = 29; RUNTIMEFERR(\"EXEC$\", ERROR, k, l); } }" TO g_FUNCTIONS
	WRITELN "else if (forking == 0) { fflush(stdout); close (wpipe[1]); close (rpipe[0]); dup2 (wpipe[0], STDIN_FILENO); close (wpipe[0]); dnull = open(\"/dev/null\", O_RDWR); if(out == 1) { dup2 (rpipe[1], STDOUT_FILENO); dup2(dnull, STDERR_FILENO); } else if (out == 2) { dup2(dnull, STDOUT_FILENO);" TO g_FUNCTIONS
	WRITELN "dup2(rpipe[1], STDERR_FILENO); } else { dup2(rpipe[1], STDOUT_FILENO); dup2(rpipe[1], STDERR_FILENO); } close (rpipe[1]); if(t == 0) { forking = system (cmd); if (WIFEXITED (forking)) result = WEXITSTATUS (forking); }" TO g_FUNCTIONS
	WRITELN "else { args = __b2c__Get_Args(cmd); if(execvp(args[0], args) < 0 ) { if (__b2c__trap) { ERROR = 29; RUNTIMEFERR (\"EXEC$\", ERROR, k, l); } } } close(dnull); _exit(result); } else { close (wpipe[0]); close (rpipe[1]); ans = (char*)malloc(", g_BUFFER_SIZE, ");" TO g_FUNCTIONS
	WRITELN "length = 0; if (str != NULL) result = write (wpipe[1], str, __b2c__len(str)); close (wpipe[1]); do { result = read (rpipe[0], ans, ", g_BUFFER_SIZE, "); if (result == -1 && __b2c__trap) { ERROR = 30; RUNTIMEFERR(\"EXEC$\", ERROR, k, l);}" TO g_FUNCTIONS
	WRITELN "if (result == 0) { break; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], length + result + 1); if(buf[idx] == NULL && __b2c__trap) { ERROR = 6; RUNTIMEFERR(\"EXEC$\", ERROR, k, l); }" TO g_FUNCTIONS
	WRITELN "memcpy(buf[idx] + length, ans, (size_t)labs(result)); length += result; } while (result > 0); __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0';" TO g_FUNCTIONS
	WRITELN "close (rpipe[0]); free (ans); wait (&RETVAL); RETVAL = WEXITSTATUS (RETVAL); } return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "filelen") OR nolex THEN
	WRITELN "long __b2c__filelen(int l, char *k, const char *x) {struct stat buf; if(stat(x, &buf) < 0 && __b2c__trap){ERROR = 24; RUNTIMEFERR(\"FILELEN\", ERROR, k, l);}" TO g_FUNCTIONS
	WRITELN "if(x == NULL || stat(x, &buf) < 0) return -1; else return(long)(buf.st_size);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "filetime") OR nolex THEN
	WRITELN "long __b2c__filetime(int l, char *k, const char *x, int y) {struct stat buf; if(stat(x, &buf) < 0 && __b2c__trap){ERROR = 24; RUNTIMEFERR(\"FILETIME\", ERROR, k, l);}" TO g_FUNCTIONS
	WRITELN "if(x == NULL || stat(x, &buf) < 0 || y < 0 || y > 2) { return -1; } switch(y) {case 0: return(long)(buf.st_atime); break;" TO g_FUNCTIONS
	WRITELN "case 1: return(long)(buf.st_mtime); break;} return(long)(buf.st_ctime);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "filetype") OR nolex THEN
	WRITELN "int __b2c__filetype(int l, char *k, const char *file) { int type = 0; struct stat buf; if(file == NULL) { return(0); } if(lstat (file, &buf) < 0 && __b2c__trap) { ERROR = 24; RUNTIMEFERR (\"FILETYPE\", ERROR, k, l); }" TO g_FUNCTIONS
	WRITELN "switch (buf.st_mode & S_IFMT) { case S_IFBLK: type = 4; break; case S_IFCHR: type = 3; break; case S_IFDIR: type = 2; break; case S_IFIFO: type = 5; break; case S_IFLNK: type = 6; break;" TO g_FUNCTIONS
	WRITELN "case S_IFREG: type = 1; break; case S_IFSOCK: type = 7; break; default: if(__b2c__trap) { ERROR = 24; RUNTIMEFERR(\"FILETYPE\", ERROR, k, l); } break; } return(type); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "fill") OR nolex THEN
	WRITELN "char * __b2c__fill (unsigned long amount, unsigned int txt) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char bf[5]; int x, len; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } if (__b2c__option_utf8) { len = __b2c_utf8_conv (txt, bf);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], amount*len+1); for (x = 0; x < (amount * len); x += len) { memcpy(buf[idx] + x, bf, len); } __b2c__SETLEN(buf[idx], amount * len); buf[idx][amount * len] = '\\0'; } else" TO g_FUNCTIONS
	WRITELN "{ buf[idx] = (char*)__b2c_str_realloc(buf[idx], amount+1); memset(buf[idx], txt, amount); __b2c__SETLEN(buf[idx], amount); buf[idx][amount] = '\\0'; } return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "flatten") OR nolex THEN
	WRITELN "char *__b2c__flatten(char *src, char *meta) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char quote[1]; long len, x, pos=0, escaped=0; quote[0] = __b2c__option_dq; if(src == NULL) { return(src); }" TO g_FUNCTIONS
	WRITELN "if (meta == NULL) { meta = quote; } len = __b2c__len(src); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+1);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx], src, len); buf[idx][len] = '\\0'; for(x = 0; src[x] != 0; x++) { if(src[x] == meta[0]) { if(!escaped) { memmove(buf[idx]+pos, src+x+1, len-x-1); }" TO g_FUNCTIONS
	WRITELN "else { pos++; escaped = 0; } } else { if(src[x] == __b2c__option_esc) { if(!escaped) { memmove(buf[idx]+pos, src+x+1, len-x-1); escaped = 1; } else { pos++; } }" TO g_FUNCTIONS
	WRITELN "else { pos++; escaped = 0; } } } __b2c__SETLEN(buf[idx], pos); buf[idx][pos] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
	WRITELN "char * __b2c__unflatten (char *src, char *meta) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char quote[1]; long x, pos = 1; quote[0] = __b2c__option_dq; if (src == NULL) { return (src); }" TO g_FUNCTIONS
	WRITELN "if (meta == NULL) { meta = quote; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], 2*__b2c__len(src)+1); buf[idx][0] = meta[0];" TO g_FUNCTIONS
	WRITELN "for (x = 0; src[x] != 0; x++) { if (src[x] == meta[0]) { buf[idx][pos++] = __b2c__option_esc; buf[idx][pos++] = src[x]; } else {buf[idx][pos++] = src[x];} } buf[idx][pos++] = meta[0];" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], pos); buf[idx][pos] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "getenviron") OR nolex THEN
	WRITELN "char *__b2c__getenv (char *env) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char *result; long len; result = getenv (env); if(result == NULL) { return(EmptyString); } len = strlen(result); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], (len+1)*sizeof(char)); strncpy(buf[idx], result, len); __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "getkey") OR nolex THEN
	WRITELN "long __b2c__getch(void){long ch; struct termios oldt, newt; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); newt.c_cc[VMIN]=1;" TO g_FUNCTIONS
	WRITELN "newt.c_cc[VTIME]=0; tcsetattr(STDIN_FILENO, TCSANOW, &newt); ch = getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); return(ch);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "getpeer") OR nolex THEN
	IF INSTR(OS$, "OSF1") THEN
		line$ = "int"
	ELSE
		line$ = "unsigned int"
	ENDIF
	WRITELN "char * __b2c__getpeer(int l, char *k, uintptr_t remote) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; struct sockaddr_in *peer; ", line$, " length = sizeof (peer); char port[6]; int desc; peer = (struct sockaddr_in*)calloc (1, sizeof(*peer));" TO g_FUNCTIONS
	IF g_OPTION_TLS THEN
		IF TALLY(g_LIB_TLS$, "gnutls") THEN
			WRITELN "if(__b2c__option_tls) { BIO_get_fd(((SSL*)remote)->gnutls_state, &desc); }" TO g_FUNCTIONS
		ELSE
			WRITELN "if(__b2c__option_tls) { desc = SSL_get_fd((SSL*)remote); }" TO g_FUNCTIONS
		ENDIF
	ENDIF
	WRITELN "if(!__b2c__option_tls) { desc = remote; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], ", g_BUFFER_SIZE, "*sizeof(char));" TO g_FUNCTIONS
	WRITELN "if (getpeername(desc, (struct sockaddr *) peer, &length) < 0) { if (__b2c__trap) { ERROR = 16; RUNTIMEFERR(\"GETPEER$\", ERROR, k, l); } else strncpy(buf[idx], \"Peer not found\", ", g_BUFFER_SIZE, "); }" TO g_FUNCTIONS
	WRITELN "else { strncpy(buf[idx], inet_ntoa (peer->sin_addr), ", g_BUFFER_SIZE, "-7); strcat(buf[idx], \":\"); snprintf (port, 6, \"%d\", ntohs (peer->sin_port)); strcat(buf[idx], port); }" TO g_FUNCTIONS
	WRITELN "free (peer); __b2c__SETLEN(buf[idx], strlen(buf[idx])); buf[idx][", g_BUFFER_SIZE, "-1] = '\\0'; return(char*)(buf[idx]);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "getxy") OR nolex THEN
	WRITELN "long __b2c__getxy(int type){char asw[", g_BUFFER_SIZE, "]; struct termios old, cnew; int len, x = 0, y = 0; tcgetattr(STDIN_FILENO, &old); cnew = old; cnew.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &cnew);" TO g_FUNCTIONS
	WRITELN "if(write(STDOUT_FILENO, \"\\033[6n\", 4)>=0){len = read(STDIN_FILENO, asw, ", g_BUFFER_SIZE, "); asw[len] = '\\0'; tcsetattr(STDIN_FILENO, TCSANOW, &old); sscanf(asw, \"\\033[%d;%dR\", &y, &x);} if (!type) return(long)x; return(long)y;}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "sortnr") OR nolex THEN
	WRITELN "int __b2c__sortnrd(const void *a, const void *b) {if (*(double*)a==*(double*)b) return(0); else if (*(double*)a < *(double*)b) return(-1); else return(1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrd_wrap(const void *a, const void *b) { return(__b2c__sortnrd(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrd_down(const void *a, const void *b) {if (*(double*)a==*(double*)b) return(0); else if (*(double*)a < *(double*)b) return(1); else return(-1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrd_wrap_down(const void *a, const void *b) { return(__b2c__sortnrd_down(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrf(const void *a, const void *b) {if (*(float*)a==*(float*)b) return(0); else if (*(float*)a < *(float*)b) return(-1); else return(1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrf_wrap(const void *a, const void *b) { return(__b2c__sortnrf(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrf_down(const void *a, const void *b) {if (*(float*)a==*(float*)b) return(0); else if (*(float*)a < *(float*)b) return(1); else return(-1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrf_wrap_down(const void *a, const void *b) { return(__b2c__sortnrf_down(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrl(const void *a, const void *b) {if (*(long*)a==*(long*)b) return(0); else if (*(long*)a < *(long*)b) return(-1); else return(1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrl_wrap(const void *a, const void *b) { return(__b2c__sortnrl(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrl_down(const void *a, const void *b) {if (*(long*)a==*(long*)b) return(0); else if (*(long*)a < *(long*)b) return(1); else return(-1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrl_wrap_down(const void *a, const void *b) { return(__b2c__sortnrl_down(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnri(const void *a, const void *b) {if (*(int*)a==*(int*)b) return(0); else if (*(int*)a < *(int*)b) return(-1); else return(1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnri_wrap(const void *a, const void *b) { return(__b2c__sortnri(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnri_down(const void *a, const void *b) {if (*(int*)a==*(int*)b) return(0); else if (*(int*)a < *(int*)b) return(1); else return(-1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnri_wrap_down(const void *a, const void *b) { return(__b2c__sortnri_down(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrs(const void *a, const void *b) {if (*(short*)a==*(short*)b) return(0); else if (*(short*)a < *(short*)b) return(-1); else return(1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrs_wrap(const void *a, const void *b) { return(__b2c__sortnrs(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrs_down(const void *a, const void *b) {if (*(short*)a==*(short*)b) return(0); else if (*(short*)a < *(short*)b) return(1); else return(-1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrs_wrap_down(const void *a, const void *b) { return(__b2c__sortnrs_down(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrc(const void *a, const void *b) {if (*(char*)a==*(char*)b) return(0); else if (*(char*)a < *(char*)b) return(-1); else return(1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrc_wrap(const void *a, const void *b) { return(__b2c__sortnrc(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrc_down(const void *a, const void *b) {if (*(char*)a==*(char*)b) return(0); else if (*(char*)a < *(char*)b) return(1); else return(-1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortnrc_wrap_down(const void *a, const void *b) { return(__b2c__sortnrc_down(*(void**)a, *(void**)b)); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "sortstr") OR nolex THEN
	WRITELN "int __b2c__sortstr(const void *a, const void *b)" TO g_FUNCTIONS
	WRITELN "{if(*(char **)a == NULL) return(-1); if(*(char **)b == NULL) return(1); return strcmp(*(char **)a, *(char **)b);}" TO g_FUNCTIONS
	WRITELN "int __b2c__sortstr_down(const void *a, const void *b)" TO g_FUNCTIONS
	WRITELN "{if(*(char **)a == NULL) return(-1); if(*(char **)b == NULL) return(1); return strcmp(*(char **)b, *(char **)a);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "malloc") OR nolex THEN
	WRITELN "char *__b2c__strdup (const char *s) { if (s == NULL) { return (NULL); } return (strdup (s)); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__strndup (const char *s, size_t n) { char *cnew; if (s == NULL) { return (NULL); } cnew = (char*)malloc(n + 1); if(cnew == NULL) return(NULL); cnew[n] = '\\0'; return (char*)strncpy(cnew, s, n); }" TO g_FUNCTIONS
	WRITELN "int __b2c__strcmp(const char *__b2c__s1, const char *__b2c__s2){if(__b2c__s1 == NULL && __b2c__s2 == NULL) return(0);" TO g_FUNCTIONS
	WRITELN "if(__b2c__s1 == NULL) { __b2c__s1 = EmptyString; } if(__b2c__s2 == NULL) { __b2c__s2 = EmptyString; } return(strcmp(__b2c__s1, __b2c__s2));}" TO g_FUNCTIONS
	WRITELN "int __b2c__strcasecmp(const char *__b2c__s1, const char *__b2c__s2){if(__b2c__s1 == NULL && __b2c__s2 == NULL) { return(0); }" TO g_FUNCTIONS
	WRITELN "if(__b2c__s1 == NULL) {return(-1); } if(__b2c__s2 == NULL) { return(1); } return(strcasecmp(__b2c__s1, __b2c__s2));}" TO g_FUNCTIONS
	WRITELN "void *__b2c_str_realloc(char *ptr, size_t size) { if (ptr == NULL || ( ((uintptr_t)ptr & 1) && __b2c__INRANGE(ptr) ? *(uint32_t*)(ptr-__b2c__BUFOFFSET+4) : 0) <= size) { if((uintptr_t)ptr & 1)" TO g_FUNCTIONS
	WRITELN "{ ptr = (char*)realloc(ptr - __b2c__BUFOFFSET, __b2c__BUFOFFSET + size * 2 + 1); } else { ptr = (char*)realloc(ptr, __b2c__BUFOFFSET + size * 2 + 1); } *(uint32_t *) ((char*)ptr + 4) = size * 2 + 1; __b2c__SETRANGE (ptr); ptr += __b2c__BUFOFFSET; } return(ptr); }" TO g_FUNCTIONS
	WRITELN "char *__b2c_Copy_String (char *x, char *y) { long ylen; if (y == NULL) { __b2c__STRFREE (x); return (NULL); }" TO g_FUNCTIONS
	WRITELN "ylen = __b2c__len (y); x = (char*)__b2c_str_realloc(x, ylen); memmove (x, y, ylen); if ((uintptr_t) x & 1) { __b2c__SETLEN (x, ylen); } x[ylen] = '\\0'; return (x); }" TO g_FUNCTIONS
	WRITELN "void __b2c_Swap_String(char **x, char **y) { if(__b2c__INRANGE(*x) && __b2c__INRANGE(*y)) { char *ptr; ptr = *x; *x = *y; *y = ptr; } else { *x = __b2c_Copy_String(*x, *y); } }" TO g_FUNCTIONS
	WRITELN "unsigned long __b2c__len (const char *ptr) { if (ptr == NULL) { return (0); } if (((uintptr_t)ptr&1) && __b2c__INRANGE(ptr)) { return (*(uint32_t *) (ptr - __b2c__BUFOFFSET)); } return ((unsigned long) strlen (ptr)); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__loop_helper(jmp_buf buf) { if(__b2c__loop_result", g_STRINGSIGN$, " != NULL) { __b2c__SETLEN (__b2c__loop_result", g_STRINGSIGN$, ", 0); __b2c__loop_result", g_STRINGSIGN$, " = __b2c_Copy_String(__b2c__loop_result", g_STRINGSIGN$, ", EmptyString); } longjmp(buf, 1); return(NULL); }" TO g_FUNCTIONS
	WRITELN "long __b2c__loop_helper2(jmp_buf buf) { __b2c__loop_result = 0; longjmp(buf, 1); return(0); }" TO g_FUNCTIONS
	WRITELN "void __b2c__free_str_array_members(char ***array, int base, int size) { int i; if(*array != NULL) { for(i=0; i < size; i++){ __b2c__STRFREE((*array)[i+base]); (*array)[i+base] = NULL; } } }" TO g_FUNCTIONS
	IF INSTR(OS$, "BSD") THEN
		WRITELN "char *__b2c_strlcat(char *dest, const char *src) { strlcat(dest, src, __b2c__len(dest)+__b2c__len(src)+1); return(dest); }" TO g_FUNCTIONS
		WRITELN "char *__b2c_strlcpy(char *dest, const char *src) { strlcpy(dest, src, __b2c__len(src)+1); return(dest); }" TO g_FUNCTIONS
	ENDIF
ENDIF

IF TALLY(total$, "hash") OR nolex THEN
	WRITELN "typedef struct __b2c__htable { char *key[65536]; void *value[65536]; char *index[65536]; int total; struct __b2c__htable *next; } __b2c__htable;" TO g_FUNCTIONS
	WRITELN "const char *__b2c__hash_key_collect(int n, const char *first, ...) { static char *keys[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long length = 0, cnew; char *next; va_list ap; if (n == 0) { return (EmptyString); }" TO g_FUNCTIONS
	WRITELN "if (n == 1) { return (first); } idx++; if (idx == __b2c_STRING_FUNC) { idx = 0; } if(keys[idx]) { free(keys[idx]); } keys[idx] = __b2c__strdup(first); length = __b2c__len(first); n--; va_start(ap, first);" TO g_FUNCTIONS
	WRITELN "while (n) { next = va_arg (ap, char *); if (next) { cnew = __b2c__len (next); keys[idx] = (char*)realloc (keys[idx], (length + cnew + 1 + 1) * sizeof(char)); keys[idx][length] = 32;" TO g_FUNCTIONS
	WRITELN "length++; memmove(keys[idx]+length, next, cnew); length += cnew; } n--; } va_end(ap); keys[idx][length] = '\\0'; return((char*)keys[idx]); }" TO g_FUNCTIONS
	WRITELN "#define __b2c__KEYCOLLECT(...) __b2c__hash_key_collect(sizeof((const char*[]){__VA_ARGS__}) / sizeof(char*), __VA_ARGS__, NULL)" TO g_FUNCTIONS
	WRITELN "uint64_t __b2c__HashFNV1a(const char *key, int len){ uint64_t hash = 14695981039346656037UL; if(key==NULL) { return(0); } if(len) { while(len) { hash = 1099511628211 * (hash ^ *key); key++; len--; } } else { while(*key) { hash = 1099511628211 * (hash ^ *key); key++; } } return(hash); }" TO g_FUNCTIONS
	WRITELN "uint16_t __b2c__HashFNV1a_16 (const char *key) { uint32_t hash = 2166136261UL; while (*key) { hash = 16777619 * (hash ^ *key); key++; } return((hash>>16) ^ (hash & 0xffff)); }" TO g_FUNCTIONS
	WRITELN "__b2c__htable *__b2c__hash_new(void) { __b2c__htable *name; name = (__b2c__htable*)calloc(1, sizeof(__b2c__htable)); name->next = NULL; name->total = 0; return(name); }" TO g_FUNCTIONS
	WRITELN "__b2c__htable* __b2c__hash_find_key_do(__b2c__htable *name, unsigned short hash, const char *key) { if(key == NULL || name == NULL) { return(NULL); } if(hash == 0) { hash = __b2c__HashFNV1a_16(key); } do" TO g_FUNCTIONS
	WRITELN "{ if(name->key[hash] && !strcmp(name->key[hash], key)) { return(name); } name = name->next; } while(name); return(NULL); }" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_find_key(x, y, ...) __b2c__hash_find_key_do(x, y, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "void *__b2c__hash_find_value_do(__b2c__htable *name, const char *key) { __b2c__htable *table; unsigned short pos; if(name == NULL || key == NULL) { return(NULL); } pos = __b2c__HashFNV1a_16(key); table = __b2c__hash_find_key(name, pos, key);" TO g_FUNCTIONS
	WRITELN "if(table) { return(table->value[pos]); } return(NULL); }" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_find_value(x, ...) __b2c__hash_find_value_do(x, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "void __b2c__hash_add_do(__b2c__htable *name, const void *value, int flag, const char *key) { unsigned short hash; if(name == NULL || key == NULL) { return; } hash = __b2c__HashFNV1a_16(key);" TO g_FUNCTIONS
	WRITELN "while(1) { if(name->key[hash] == NULL) { name->total++; break; } if(!strcmp(name->key[hash], key)) { if(flag != 2) { break; } } if(name->next) { name = name->next; } else { name->next = __b2c__hash_new(); name = name->next;} }" TO g_FUNCTIONS
	WRITELN "if(!name->key[hash]) { name->key[hash] = strdup(key); name->index[name->total-1] = name->key[hash]; } if(flag == 0) { if(!name->value[hash]) { name->value[hash] = calloc(1, sizeof(void*)); } memcpy(name->value[hash], value, sizeof(void*)); } else" TO g_FUNCTIONS
	WRITELN "{ name->value[hash] = realloc(name->value[hash], __b2c__len((char*)value)+1); strcpy((char*)name->value[hash], (const char*)value); } }" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_add(x, y, ...) __b2c__hash_add_do(x, y, 0, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_add_str(x, y, ...) __b2c__hash_add_do(x, y, 1, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_add_redundant(x, y, ...) __b2c__hash_add_do(x, y, 2, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "void *__b2c__hash_realloc_str_value_do(__b2c__htable *name, int len, const char *key) { __b2c__htable *table; unsigned short pos; if (name == NULL || key == NULL) { return (NULL); } __b2c__hash_add_str(name, \"\", key); pos = __b2c__HashFNV1a_16(key);" TO g_FUNCTIONS
	WRITELN "table = __b2c__hash_find_key(name, pos, key); table->value[pos] = realloc(table->value[pos], len); return (table->value[pos]); }" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_realloc_str_value(x, y, ...) __b2c__hash_realloc_str_value_do(x, y, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "void __b2c__hash_del_do(__b2c__htable *name, int rebuild, const char *key) { __b2c__htable *found; unsigned short pos; int i, which; if(name == NULL) { return; } pos = __b2c__HashFNV1a_16(key); found = __b2c__hash_find_key(name, pos, key);" TO g_FUNCTIONS
	WRITELN "if(found) { if (rebuild) { for (i = 0; i < found->total; i++) { which = __b2c__HashFNV1a_16(found->index[i]); if (which == pos) { if(i != found->total-1) { found->index[i] = found->index[found->total-1]; } found->index[found->total-1] = NULL; break; } } }" TO g_FUNCTIONS
	WRITELN "free(found->key[pos]); found->key[pos] = NULL; if(found->value[pos]) { free(found->value[pos]); } found->value[pos] = NULL; found->total -= 1; } }" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_del(x, ...) __b2c__hash_del_do(x, 1, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_del_norebuild(x, ...) __b2c__hash_del_do(x, 0, __b2c__KEYCOLLECT(__VA_ARGS__))" TO g_FUNCTIONS
	WRITELN "void __b2c__hash_clear_do(__b2c__htable *name) { __b2c__htable *orig, *next; int i; orig = name; while(name) { for(i = 0; i < 65536; i++) { if(name->key[i]) { free(name->key[i]); } name->key[i] = NULL;" TO g_FUNCTIONS
	WRITELN "if(name->value[i]) { free(name->value[i]); } name->value[i] = NULL; } next = name->next; name->next = NULL; name->total = 0; if(name != orig) { free(name); } name = next; } }" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_clear(x) __b2c__hash_clear_do(x)" TO g_FUNCTIONS
	WRITELN "int __b2c__hash_nrkeys(__b2c__htable *name) { int total = 0; while(name) { total += name->total; name = name->next; } return(total); }" TO g_FUNCTIONS
	WRITELN "void __b2c__hash_dup_do(__b2c__htable *from, __b2c__htable *to, int flag) { int i; char *value; while(from) { for(i = 0; i < 65536; i++) { if(from->key[i]) { value = (char*)__b2c__hash_find_value(from, from->key[i]); if(flag==0) { __b2c__hash_add(to, value, from->key[i]); } " TO g_FUNCTIONS
	WRITELN "else { __b2c__hash_add_str(to, value, from->key[i]); } } } from = from->next; if(to->next == NULL) { to->next = __b2c__hash_new(); } to = to->next; } }" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_dup(x, y) __b2c__hash_dup_do(x, y, 0)" TO g_FUNCTIONS
	WRITELN "#define __b2c__hash_dup_str(x, y) __b2c__hash_dup_do(x, y, 1)" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "obtain") OR nolex THEN
	WRITELN "char *__b2c__hash_obtain(__b2c__htable *name, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long ctr, dlen, len, total = 0; if(name == NULL) { return (EmptyString); } if(delim == NULL) { delim = __b2c__option_delim; }" TO g_FUNCTIONS
	WRITELN "if(name->total == 0) { return (EmptyString); } dlen = __b2c__len(delim); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], dlen); do { for(ctr=0; ctr < name->total; ctr++) { len = __b2c__len(name->index[ctr]);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], total+len+dlen); memmove(buf[idx] + total, name->index[ctr], len); total += len; memmove(buf[idx] + total, delim, dlen); total += dlen; } name = name->next; }" TO g_FUNCTIONS
	WRITELN "while(name); __b2c__SETLEN(buf[idx], total-dlen); buf[idx][total-dlen] = '\\0'; return((char*)buf[idx]); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__hash_obtain_by_sort(int l, char *k, __b2c__htable * name, char *delim, int up_down, int type) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; void **values = { NULL }; char **keys = { NULL }; void **dups = { NULL }; __b2c__htable *ptr, *inv; int i, j, pos = 0, start = 0, cur = 0; long dlen, len, total = 0;" TO g_FUNCTIONS
	WRITELN "char bf[", g_MAX_DIGITS, " + 1]; if (name == NULL || name->total == 0) { return (EmptyString); } if (delim == NULL) { delim = __b2c__option_delim; } values = (void **) calloc (__b2c__hash_nrkeys (name), sizeof (char *)); inv = __b2c__hash_new (); ptr = name; do { for (i = 0; i < 65536; i++) { if (ptr->key[i]) { switch (type)" TO g_FUNCTIONS
	WRITELN "{ case 0: snprintf (bf, ", g_MAX_DIGITS, ", \"%s\", (char *) ptr->value[i]); break; case 1: snprintf (bf, ", g_MAX_DIGITS, ", \"%g\", *(double *) ptr->value[i]); break; case 2: snprintf (bf, ", g_MAX_DIGITS, ", \"%g\", *(float *) ptr->value[i]); break;" TO g_FUNCTIONS
	WRITELN "case 3: snprintf (bf, ", g_MAX_DIGITS, ", \"%ld\", *(long *) ptr->value[i]); break; case 4: snprintf (bf, ", g_MAX_DIGITS, ", \"%d\", *(int *) ptr->value[i]); break; case 5: snprintf (bf, ", g_MAX_DIGITS, ", \"%d\", *(short *) ptr->value[i]); break;" TO g_FUNCTIONS
	WRITELN "case 6: snprintf (bf, ", g_MAX_DIGITS, ", \"%d\", *(char *) ptr->value[i]); break; default: if (__b2c__trap) { ERROR = 43; RUNTIMEFERR(\"OBTAIN$\", ERROR, k, l); } } __b2c__hash_add_redundant(inv, ptr->key[i], bf); values[pos++] = ptr->value[i]; } } ptr = ptr->next; } while (ptr);" TO g_FUNCTIONS
	WRITELN "switch (type) { case 0: if (up_down) { qsort (&values[0], pos, sizeof (void *), __b2c__sortstr); } else { qsort (&values[0], pos, sizeof (void *), __b2c__sortstr_down); } break; case 1: if (up_down) { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrd_wrap); }" TO g_FUNCTIONS
	WRITELN "else { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrd_wrap_down); } break; case 2: if (up_down) { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrf_wrap); } else { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrf_wrap_down); } break;" TO g_FUNCTIONS
	WRITELN "case 3: if (up_down) { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrl_wrap); } else { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrl_wrap_down); } break; case 4: if (up_down) { qsort (&values[0], pos, sizeof (void *), __b2c__sortnri_wrap); }" TO g_FUNCTIONS
	WRITELN "else { qsort (&values[0], pos, sizeof (void *), __b2c__sortnri_wrap_down); } break; case 5: if (up_down) { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrs_wrap); } else { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrs_wrap_down); } break;" TO g_FUNCTIONS
	WRITELN "case 6: if (up_down) { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrc_wrap); } else { qsort (&values[0], pos, sizeof (void *), __b2c__sortnrc_wrap_down); } break; } dlen = __b2c__len (delim); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], dlen);" TO g_FUNCTIONS
	WRITELN "keys = (char**)calloc(__b2c__hash_nrkeys(name), sizeof(char*)); dups = (void**)calloc(__b2c__hash_nrkeys(name), sizeof(void*)); for(i = 0; i < pos; i++) { keys[i] = (char*)calloc(", g_MAX_DIGITS, ", sizeof(char)); switch (type)" TO g_FUNCTIONS
	WRITELN "{ case 0: snprintf (keys[i], ", g_MAX_DIGITS, ", \"%s\", (char *) values[i]); break; case 1: snprintf (keys[i], ", g_MAX_DIGITS, ", \"%g\", *(double *) values[i]); break; case 2: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%g\", *(float*)values[i]); break;" TO g_FUNCTIONS
	WRITELN "case 3: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%ld\", *(long *) values[i]); break; case 4: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%d\", *(int *) values[i]); break; case 5: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%d\", *(short*)values[i]); break; case 6:" TO g_FUNCTIONS
	WRITELN "snprintf(keys[i], ", g_MAX_DIGITS, ", \"%d\", *(char *) values[i]); break; } dups[i] = __b2c__strdup((char*)__b2c__hash_find_value_do (inv, keys[i])); __b2c__hash_del_norebuild (inv, keys[i]); }" TO g_FUNCTIONS
	WRITELN "do { if(type == 0) { while(cur < pos-1 && !strcmp(keys[cur], keys[cur+1])) { cur++; } } else { while(cur < pos-1 && !memcmp(keys[cur], keys[cur+1], sizeof(void*))) { cur++; } } qsort (&dups[start], cur-start+1, sizeof (char *), __b2c__sortstr);" TO g_FUNCTIONS
	WRITELN "for (j = start; j <= cur; j++) { len = __b2c__len ((char *) dups[j]); buf[idx] = (char*)__b2c_str_realloc(buf[idx], total + len + dlen);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + total, dups[j], len); free(dups[j]); free(keys[j]); total += len; memmove(buf[idx] + total, delim, dlen); total += dlen; } cur++; start = cur; } while(cur < pos);" TO g_FUNCTIONS
	WRITELN "__b2c__hash_clear (inv); free(inv); free(values); free(dups); free(keys); total -= dlen; __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return((char*)buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "lookup") OR nolex THEN
	WRITELN "int __b2c__lookup_by_order(__b2c__htable *name, char ***array, int size, int base) { int i, count = 0; if(name) { if(*array) { __b2c__free_str_array_members (&(*array), base, size); free(*array); } *array = (char **)calloc(__b2c__hash_nrkeys(name)+base, sizeof(char*));" TO g_FUNCTIONS
	WRITELN "count = base; do { for(i = 0; i < name->total; i++) { (*array)[count++] = __b2c__strdup(name->index[i]); } name = name->next; } while(name); count -= base; } return(count); }" TO g_FUNCTIONS
	WRITELN "int __b2c__lookup_by_sort (__b2c__htable * name, char ***array, int size, int base, int type, int (*compare)(const void*, const void*)) { void **values = { NULL }; char **keys = { NULL }; __b2c__htable *ptr, *inv; char *value; int i, j, pos = 0, count = 0, cur = 0, start = 0; char buf[", g_MAX_DIGITS, " + 1];" TO g_FUNCTIONS
	WRITELN "if (*array) { __b2c__free_str_array_members (&(*array), base, size); free (*array); } if (name) { values = (void **) calloc (__b2c__hash_nrkeys (name), sizeof (char *)); inv = __b2c__hash_new (); ptr = name; do" TO g_FUNCTIONS
	WRITELN "{ for (i = 0; i < 65536; i++) { if (ptr->key[i]) { switch (type) { case 0: snprintf (buf, ", g_MAX_DIGITS, ", \"%s\", (char *) ptr->value[i]); break; case 1: snprintf (buf, ", g_MAX_DIGITS, ", \"%g\", *(double *) ptr->value[i]); break; case 2: snprintf (buf, ", g_MAX_DIGITS, ", \"%g\", *(float *) ptr->value[i]);" TO g_FUNCTIONS
	WRITELN "break; case 3: snprintf (buf, ", g_MAX_DIGITS, ", \"%ld\", *(long *) ptr->value[i]); break; case 4: snprintf (buf, ", g_MAX_DIGITS, ", \"%d\", *(int *) ptr->value[i]); break; case 5: snprintf (buf, ", g_MAX_DIGITS, ", \"%d\", *(short *) ptr->value[i]); break; case 6: snprintf (buf, ", g_MAX_DIGITS, ", \"%d\", *(char *) ptr->value[i]);" TO g_FUNCTIONS
	WRITELN "break; } __b2c__hash_add_redundant(inv, ptr->key[i], buf); values[pos++] = ptr->value[i]; } } ptr = ptr->next; } while (ptr); qsort (&values[0], pos, sizeof (void *), compare); *array = (char**)calloc(__b2c__hash_nrkeys(name) + base, sizeof(char*)); keys = (char**)calloc(__b2c__hash_nrkeys(name) + base, sizeof(char*));" TO g_FUNCTIONS
	WRITELN "count = base; for (i = 0; i < pos; i++) { keys[i] = (char*)calloc(", g_MAX_DIGITS, ", sizeof(char)); switch (type) { case 0: snprintf (keys[i], ", g_MAX_DIGITS, ", \"%s\", (char *) values[i]); break; case 1: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%g\", *(double *) values[i]); break; case 2: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%g\", *(float *) values[i]); break;" TO g_FUNCTIONS
	WRITELN "case 3: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%ld\", *(long *) values[i]); break; case 4: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%d\", *(int *) values[i]); break; case 5: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%d\", *(short *) values[i]); break; case 6: snprintf(keys[i], ", g_MAX_DIGITS, ", \"%d\", *(char *) values[i]); break; }" TO g_FUNCTIONS
	WRITELN "value = (char*)__b2c__hash_find_value_do(inv, keys[i]); (*array)[count++] = __b2c__strdup (value); __b2c__hash_del_norebuild (inv, keys[i]); } do { if (type == 0) { while (cur < pos - 1 && !strcmp (keys[cur], keys[cur + 1])) { cur++; } } else { while (cur < pos - 1 && !memcmp (keys[cur], keys[cur + 1], sizeof(void*))) { cur++; }}" TO g_FUNCTIONS
	WRITELN "qsort(&(*array)[start+base], cur - start + 1, sizeof(char*), __b2c__sortstr); for (j = start; j <= cur; j++) { free (keys[j]); } cur++; start = cur; } while (cur < pos); __b2c__hash_clear (inv); free (inv); free (values);" TO g_FUNCTIONS
	WRITELN "free (keys); count -= base; } return (count); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "hex") OR nolex THEN
	WRITELN "char *__b2c__dec2hex(int nr) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; int len; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], ", g_MAX_DIGITS, ");" TO g_FUNCTIONS
	WRITELN "len = snprintf(buf[idx], ", g_MAX_DIGITS, ", \"%X\", nr); __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "host") OR nolex THEN
	WRITELN "char *__b2c__nethost(int l, char *k, char *host) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; int y, flag = 0; struct hostent *he = NULL; unsigned char bf[sizeof(struct sockaddr_in*)]; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], ", g_BUFFER_SIZE, "); for (y = 0; host[y] != '\\0'; y++) { if (isalpha (*(host + y))) { flag = 1; break; } } if (flag){ he = gethostbyname (host); strncpy(buf[idx], inet_ntoa(*((struct in_addr*)he->h_addr)), ", g_BUFFER_SIZE, "); }" TO g_FUNCTIONS
	WRITELN "else { if (inet_pton(AF_INET, host, bf) <= 0) { if (__b2c__trap) { ERROR = 11; RUNTIMEFERR (\"HOST$\", ERROR, k, l); } else { strncpy(buf[idx], \"Host not found\", ", g_BUFFER_SIZE, "); } }" TO g_FUNCTIONS
	WRITELN "else { he = gethostbyaddr(bf, sizeof(struct sockaddr_in*), AF_INET); if(he == NULL) { if (__b2c__trap) { ERROR = 11; RUNTIMEFERR (\"HOST$\", ERROR, k, l); } else { strncpy(buf[idx], \"Host not found\", ", g_BUFFER_SIZE, "); } } else { strncpy(buf[idx], he->h_name, ", g_BUFFER_SIZE, "); } } }" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], strlen(buf[idx])); buf[idx][", g_BUFFER_SIZE, "-1] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "hostname") OR nolex THEN
	WRITELN "char *__b2c__hostname(int l, char *k) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], ", g_BUFFER_SIZE, " * sizeof (char));" TO g_FUNCTIONS
	WRITELN "if(gethostname(buf[idx], ", g_BUFFER_SIZE, ")) { if (__b2c__trap) { ERROR = 26; RUNTIMEFERR(\"HOSTNAME$\", ERROR, k, l); } else strncpy (buf[idx], \"Error getting hostname\", ", g_BUFFER_SIZE, "); }" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], strlen(buf[idx])); buf[idx][", g_BUFFER_SIZE, "-1] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "index") OR nolex THEN
    WRITELN "int __b2c__index (int line, char *k, size_t range, int type, void *array, int flag, ...) { int result = 0 + ", g_OPTION_BASE, "; double d; float f; long l; int i; short s; char c; char *term; void *index; int len = 0; va_list ap; va_start (ap, flag); if (flag == 0) { switch (type)" TO g_FUNCTIONS
    WRITELN "{ case 0: term = va_arg(ap, char*); if ((index = lfind (&term, array, &range, sizeof (char *), __b2c__sortstr)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (char *) + 1; } break; case 1: d = va_arg (ap, double); if ((index = lfind (&d, array, &range, sizeof (double), __b2c__sortnrd)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (double) + 1; } break;" TO g_FUNCTIONS
    WRITELN "case 2: f = va_arg (ap, double); if ((index = lfind (&f, array, &range, sizeof (float), __b2c__sortnrf)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (float) + 1; } break; case 3: l = va_arg (ap, long); if ((index = lfind (&l, array, &range, sizeof (long), __b2c__sortnrl)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (long) + 1; } break;" TO g_FUNCTIONS
    WRITELN "case 4: i = va_arg (ap, int); if ((index = lfind (&i, array, &range, sizeof (int), __b2c__sortnri)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (int) + 1; } break; case 5: s = va_arg (ap, int); if ((index = lfind (&s, array, &range, sizeof (short), __b2c__sortnrs)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (short) + 1; } break;" TO g_FUNCTIONS
    WRITELN "case 6: c = va_arg (ap, int); if ((index = lfind (&c, array, &range, sizeof (char), __b2c__sortnrc)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (char) + 1; } break; default: if (__b2c__trap) { ERROR = 43; RUNTIMEFERR (\"INDEX\", ERROR, k, line); } } } else { switch (type)" TO g_FUNCTIONS
    WRITELN "{ case 0: term = va_arg(ap, char*); if ((index = bsearch (&term, array, range, sizeof (char *), __b2c__sortstr)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (char *) + 1; } break; case 1: d = va_arg (ap, double); if ((index = bsearch (&d, array, range, sizeof (double), __b2c__sortnrd)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (double) + 1; } break;" TO g_FUNCTIONS
    WRITELN "case 2: f = va_arg (ap, double); if ((index = bsearch (&f, array, range, sizeof (float), __b2c__sortnrf)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (float) + 1; } break; case 3: l = va_arg (ap, long); if ((index = bsearch (&l, array, range, sizeof (long), __b2c__sortnrl)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (long) + 1; } break;" TO g_FUNCTIONS
    WRITELN "case 4: i = va_arg (ap, int); if ((index = bsearch (&i, array, range, sizeof (int), __b2c__sortnri)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (int) + 1; } break; case 5: s = va_arg (ap, int); if ((index = bsearch (&s, array, range, sizeof (short), __b2c__sortnrs)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (short) + 1; } break;" TO g_FUNCTIONS
    WRITELN "case 6: c = va_arg (ap, int); if ((index = bsearch (&c, array, range, sizeof (char), __b2c__sortnrc)) != NULL) { result = ((uintptr_t) index - (uintptr_t) array) / sizeof (char) + 1; } break; default: if (__b2c__trap) { ERROR = 43; RUNTIMEFERR (\"INDEX\", ERROR, k, line); } } } va_end (ap); return (result - ", g_OPTION_BASE, "); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "insert") OR nolex THEN
	WRITELN "char * __b2c__insert (int l, char *k, char *src, int pos, char *str) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long len, tot, blen; if (src == NULL || str == NULL) { return (src); } len = __b2c__len (src); tot = __b2c__len (str);" TO g_FUNCTIONS
	WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+tot+1); pos--; if (pos <= 0) { memmove(buf[idx], str, tot); memmove(buf[idx] + tot, src, len); } else if (pos > len) { memmove(buf[idx], src, len);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + len, str, tot); } else { if (__b2c__option_utf8) { blen = __b2c__blen (l, k, \"INSERT$\", src, pos, 0); memmove(buf[idx], src, blen); memmove(buf[idx] + blen, str, tot);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + blen + tot, src + blen, len - blen); } else { memmove(buf[idx], src, pos); memmove(buf[idx] + pos, str, tot); memmove(buf[idx] + pos + tot, src + pos, len - pos); } }" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], len + tot); buf[idx][len + tot] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "instring") OR nolex THEN
	WRITELN "long __b2c__instr(int l, char *k, char *first, char *tmp, int pos) { char *result; if (first == NULL) { return (0); } if (tmp == NULL || __b2c__len (tmp) == 0) { return (0); } if (pos <= 0) { pos = 1; }" TO g_FUNCTIONS
	WRITELN "result = strstr (first + pos - 1, tmp); if(result == NULL) { return (0); } if (__b2c__option_utf8) { return (long) __b2c__ucs2_clen (l, k, \"INSTR\", first, result - first + 1); } return (long) (result - first + 1); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "instrrev") OR nolex THEN
	WRITELN "long __b2c__instrrev(int m, char *k, char *first, char *tmp, int pos) { char *result, *found; long l; if (first == NULL){ return (0);} if (tmp == NULL || __b2c__len (tmp) == 0) { return (0); } if (pos < 0) { pos = 0; }" TO g_FUNCTIONS
	WRITELN "l = __b2c__len (first); found = first; do { result = strstr (found, tmp); if (result != NULL && result <= first + l - pos) { found = result + 1; continue; } if (result > first + l - pos) result = NULL; } while (result != NULL);" TO g_FUNCTIONS
	WRITELN "if (__b2c__option_startpoint) { if (l - (found - first) + 1 > l) { return(0); } if (__b2c__option_utf8) { return (long) (__b2c__ulen (l, k, \"INSTRREV\", first, -1) - __b2c__ucs2_clen (l, k, \"INSTRREV\", first, found - first) + 1); }" TO g_FUNCTIONS
	WRITELN "return (long) (l - (found - first) + 1); } if (__b2c__option_utf8) { return (long) __b2c__ucs2_clen (m, k, \"INSTRREV\", first, found - first); } return (long) (found - first); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "lcase") OR nolex THEN
	WRITELN "char * __b2c__lcase(int l, char *k, char *src) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long len, i; size_t mbslen; wchar_t *wcs, *wp; char *local; if (src == NULL) { return (NULL); } len = __b2c__len (src); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], len+1); if (__b2c__option_utf8) { local = setlocale (LC_ALL, \"\"); if ((mbslen = mbstowcs (NULL, src, 0)) == (size_t) - 1) { ERROR = 38; RUNTIMEFERR (\"LCASE$\", ERROR, k, l); } wcs = (wchar_t*)calloc (mbslen + 1, sizeof (wchar_t));" TO g_FUNCTIONS
	WRITELN "if(mbstowcs(wcs, src, mbslen + 1) == (size_t)-1) { ERROR = 38; RUNTIMEFERR (\"LCASE$\", ERROR, k, l); } for (wp = wcs; *wp != 0; wp++) { *wp = towlower (*wp); } if(wcstombs(buf[idx], wcs, len) == (size_t)-1) { ERROR = 38; RUNTIMEFERR (\"LCASE$\", ERROR, k, l); } free (wcs);" TO g_FUNCTIONS
	WRITELN "setlocale (LC_ALL, local); } else { for (i = 0; i < len; i++) { buf[idx][i] = tolower(src[i]); } } __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "left") OR nolex THEN
	WRITELN "char * __b2c__left(int l, char *k, char *src, unsigned long n) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; unsigned long length; if (src == NULL) { return (NULL); } idx++; if (idx == __b2c_STRING_FUNC) { idx = 0; } length = __b2c__len (src);" TO g_FUNCTIONS
	WRITELN "if (n > (__b2c__option_utf8 ? __b2c__ucs2_clen (l, k, \"LEFT$\", src, length) : length)) { buf[idx] = (char *) __b2c_str_realloc (buf[idx], length + 1); memmove (buf[idx], src, length); __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; } else { if (__b2c__option_utf8)" TO g_FUNCTIONS
	WRITELN "{ n = __b2c__blen (l, k, \"LEFT$\", src, n, 0); } buf[idx] = (char *) __b2c_str_realloc (buf[idx], n+1); memmove(buf[idx], src, n); __b2c__SETLEN (buf[idx], n); buf[idx][n] = '\\0'; } return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "load") OR nolex THEN
	WRITELN "char* __b2c__load(int flag, int l, char *k, char *file) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; FILE *handle; struct stat bf; void* mem; handle = fopen ((const char*)file, \"r\"); if(handle == NULL && __b2c__trap)" TO g_FUNCTIONS
	WRITELN "{ ERROR = 2; RUNTIMEFERR (\"LOAD$/BLOAD\", ERROR, k, l); } if(stat(file, &bf) < 0 && __b2c__trap) { ERROR = 24; RUNTIMEFERR (\"LOAD$/BLOAD\", ERROR, k, l); } if(flag) { mem = malloc(bf.st_size);" TO g_FUNCTIONS
	WRITELN "if(fread (mem, sizeof (char), bf.st_size, handle) != bf.st_size && __b2c__trap) { ERROR = 2; RUNTIMEFERR(\"BLOAD\", ERROR, k, l); } fclose(handle); return(char*)(mem); } else" TO g_FUNCTIONS
	WRITELN "{ idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], bf.st_size + 1); if(fread(buf[idx], sizeof (char), bf.st_size, handle) != bf.st_size && __b2c__trap)" TO g_FUNCTIONS
	WRITELN "{ ERROR = 2; RUNTIMEFERR (\"LOAD$\", ERROR, k, l); } __b2c__SETLEN(buf[idx], bf.st_size); buf[idx][bf.st_size] = '\\0'; fclose(handle); return(char*)(buf[idx]); } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "memcheck") OR nolex THEN
	WRITELN "void __b2c__catch_signal(int sig){" TO g_FUNCTIONS
	WRITELN "switch (sig) {case SIGABRT: fprintf(stderr, \"ERROR: signal ABORT received - internal error. Try to compile the program with TRAP LOCAL to find the cause.\\n\"); break;" TO g_FUNCTIONS
	WRITELN "case SIGFPE: fprintf(stderr, \"ERROR: signal for FPE received - division by zero? Examine the calculations in the program.\\n\"); break;" TO g_FUNCTIONS
	WRITELN "case SIGSEGV: fprintf(stderr, \"ERROR: signal for SEGMENTATION FAULT received - memory invalid or array out of bounds? Try to compile the program with TRAP LOCAL to find the cause.\\n\"); break;" TO g_FUNCTIONS
	WRITELN "case SIGILL: fprintf(stderr, \"ERROR: signal for ILLEGAL INSTRUCTION received - executing the program on other hardware? Try to recompile the program from scratch.\\n\"); break;} exit(sig);}" TO g_FUNCTIONS
	WRITELN "void __b2c__segv(int sig){longjmp(__b2c__jump, 1);}" TO g_FUNCTIONS
	WRITELN "int __b2c__memory__check(volatile char* x, int size){int i, illegal = 0; void(*handler)(int); handler = signal(SIGSEGV, __b2c__segv);" TO g_FUNCTIONS
	WRITELN "if(!setjmp(__b2c__jump)) {for(i = 0; i < size; i++) if(*(x+i)) continue;} else illegal = 1;" TO g_FUNCTIONS
	WRITELN "if(__b2c__trap) signal(SIGSEGV, __b2c__catch_signal); else signal(SIGSEGV, handler); return(illegal);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "mid") OR nolex THEN
	WRITELN "char *__b2c__mid(int l, char *k, char *src, long pos, long length) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long src_len; if (src == NULL) { return (EmptyString); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "src_len = __b2c__len (src); pos -= 1; if (pos < 0) { pos = (__b2c__option_utf8 ? __b2c__ucs2_clen (l, k, \"MID$\", src, src_len) : src_len) + 1 + pos; } if (__b2c__option_utf8) { pos = __b2c__blen (l, k, \"MID$\", src, pos, 0); }" TO g_FUNCTIONS
	WRITELN "if (pos > src_len) { return (EmptyString); } if (__b2c__option_utf8 && length >= 0) { length = __b2c__blen (l, k, \"MID$\", src + pos, length, 0); } if (length < 0 || pos + length > src_len)" TO g_FUNCTIONS
	WRITELN "{ length = src_len - pos; } buf[idx] = (char *) __b2c_str_realloc (buf[idx], length + 1); memmove (buf[idx], src + pos, length); __b2c__SETLEN (buf[idx], length); buf[idx][length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "minmax") OR nolex THEN
	WRITELN "char* __b2c__min_str(char* x, char* y) {if(strcmp(x, y) < 0) { return(x); } return(y);}" TO g_FUNCTIONS
	WRITELN "char* __b2c__max_str(char* x, char* y) {if(strcmp(x, y) > 0) { return(x); } return(y);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "os") OR nolex THEN
	WRITELN "char * __b2c__os(int l, char *k) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; struct utsname bf; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], ", g_BUFFER_SIZE, "*sizeof (char)); if(uname(&bf) < 0 && __b2c__trap) { ERROR = 26; RUNTIMEFERR(\"OS$\", ERROR, k, l); } strcpy(buf[idx], bf.sysname);" TO g_FUNCTIONS
	WRITELN "strcat(buf[idx], \" \"); strcat(buf[idx], bf.machine); __b2c__SETLEN(buf[idx], strlen(buf[idx])); return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "peek") OR nolex THEN
	WRITELN "int __b2c__peek_check(int l, char *k, char* x, int size) {if(__b2c__trap) {if(__b2c__memory__check((char*)x, size)) {ERROR=1; RUNTIMEFERR(\"PEEK\", ERROR, k, l);} } return(0); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "recursive") OR nolex THEN
	WRITELN "int __b2c__rmrecursive(int l, char *k, char *dir){DIR *mydir; char *path, *item = NULL; struct stat buf = { 0 }; struct dirent *next = { NULL }; mydir = opendir(dir); if(mydir == NULL) {if(__b2c__trap) {ERROR = 8; RUNTIMEFERR(\"DELETE RECURSIVE\", ERROR, k, l);} }" TO g_FUNCTIONS
	WRITELN "while (1) { if (item != NULL) free(item); next = readdir(mydir); if(next != NULL) { item = (char*)calloc((strlen (next->d_name) + 1), sizeof(char));" TO g_FUNCTIONS
	WRITELN "strcpy(item, next->d_name); } else { break; } if (!strcmp (item, \".\") || !strcmp(item, \"..\") ) continue; path = (char*)calloc(strlen(dir)+strlen(item)+2, sizeof(char));" TO g_FUNCTIONS
	WRITELN "strcpy(path, dir); strcat(path, \"/\"); strcat(path, item); lstat(path, &buf); if(S_ISDIR (buf.st_mode)) { __b2c__rmrecursive(l, k, path); } else { if(remove(path) < 0)" TO g_FUNCTIONS
	WRITELN "{ if(__b2c__trap) { ERROR = 7; RUNTIMEFERR(\"DELETE RECURSIVE\", ERROR, k, l); } } } if(path != NULL) free(path); } closedir(mydir); if(remove(dir) < 0)" TO g_FUNCTIONS
	WRITELN "{ if(__b2c__trap) { ERROR = 7; RUNTIMEFERR(\"DELETE RECURSIVE\", ERROR, k, l); } } return(0);}" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "reverse") OR nolex THEN
	WRITELN "char *__b2c__reverse(int l, char *k, char *src) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long i, length, len, blen; if (src == NULL) { return (EmptyString); } length = __b2c__len (src); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], length+1); if(__b2c__option_utf8) { len = length; while (len > 0) { blen = __b2c__blen (l, k, \"REVERSE$\", src, 1, 0); memcpy(buf[idx] + len - blen, src, blen); src += blen; len -= blen; } } else" TO g_FUNCTIONS
	WRITELN "{ for (i = 0; i < length; i++) { buf[idx][i] = src[length-i-1]; } } __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "right") OR nolex THEN
	WRITELN "char * __b2c__right (int l, char *k, char *src, unsigned long n) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; unsigned long length; if (src == NULL) { return (NULL); } idx++; if (idx == __b2c_STRING_FUNC) { idx = 0; } length = __b2c__len (src);" TO g_FUNCTIONS
	WRITELN "if (n > (__b2c__option_utf8 ? __b2c__ucs2_clen (l, k, \"RIGHT$\", src, length) : length)) { buf[idx] = (char *) __b2c_str_realloc (buf[idx], length + 1); memmove(buf[idx], src, length); __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; } else { if (__b2c__option_utf8)" TO g_FUNCTIONS
	WRITELN "{ n = __b2c__blen (l, k, \"RIGHT$\", src, n, 1); } buf[idx] = (char*)__b2c_str_realloc(buf[idx], n+1); memmove(buf[idx], src + length - n, n); __b2c__SETLEN(buf[idx], n); buf[idx][n] = '\\0'; } return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "rip") OR nolex THEN
	WRITELN "char *__b2c__rip(int l, char *k, char *src, long pos, long length) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long src_len; if (src == NULL) { return (EmptyString); } src_len = __b2c__len (src); pos -= 1;" TO g_FUNCTIONS
	WRITELN "if (pos < 0) { pos = (__b2c__option_utf8 ? __b2c__ucs2_clen (l, k, \"RIP$\", src, src_len) : src_len) + 1 + pos; } if (__b2c__option_utf8) { pos = __b2c__blen (l, k, \"RIP$\", src, pos, 0); } if (pos > src_len)" TO g_FUNCTIONS
	WRITELN "{ return (EmptyString); } if (__b2c__option_utf8 && length >= 0) { length = __b2c__blen (l, k, \"RIP$\", src + pos, length, 0); } if (length < 0 || pos + length > src_len)" TO g_FUNCTIONS
	WRITELN "{ length = src_len - pos; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], src_len); memmove(buf[idx], src, pos); memmove(buf[idx]+pos, src+pos+length, src_len-pos-length);" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], src_len-length); buf[idx][src_len-length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "screen") OR nolex THEN
	WRITELN "long __b2c__screen(int type){long x; struct winsize tmp; ioctl(STDOUT_FILENO, TIOCGWINSZ, &tmp); if(type) { x = tmp.ws_row; } else { x = tmp.ws_col; } return(x); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "search") OR nolex THEN
	WRITELN "long __b2c__search (int l, char *k, FILE * x, char *y, int whence) { long off, pos=0, org_pos; int flag = 0; char *ptr; if (x == NULL && __b2c__trap)" TO g_FUNCTIONS
	WRITELN "{ ERROR = 2; RUNTIMEFERR (\"SEARCH\", ERROR, k, l); } if (y == NULL && __b2c__trap) { ERROR = 25; RUNTIMEFERR (\"SEARCH\", ERROR, k, l); } org_pos = ftell (x); ptr = (char *) malloc (__b2c__len (y) + 1);" TO g_FUNCTIONS
	WRITELN "switch(whence) { case -1: case 0: off = 1; break; case 1: off = 1; break; case 2: off = -1; break; case 3: off = -1; break; default: ERROR = 37; RUNTIMEFERR (\"SEARCH\", ERROR, k, l); } do { switch(whence) { case -1: case 0: fseek (x, pos, SEEK_SET);" TO g_FUNCTIONS
	WRITELN "break; case 1: fseek (x, org_pos+pos, SEEK_SET);break; case 2: flag = fseek (x, org_pos- __b2c__len (y)+pos, SEEK_SET); break; case 3: fseek (x, pos-__b2c__len (y), SEEK_END); break; }" TO g_FUNCTIONS
	WRITELN "if (fread (ptr, sizeof (char), __b2c__len (y), x) <= 0) { if (__b2c__trap) { ERROR = 2; RUNTIMEFERR (\"SEARCH\", ERROR, k, l); } } pos += off; } while (!feof (x) && !flag && memcmp (ptr, y, __b2c__len (y)));" TO g_FUNCTIONS
	WRITELN "if (memcmp (ptr, y, __b2c__len (y))) { pos = -1; } else {pos = ftell(x)-__b2c__len (y); } fseek (x, org_pos, SEEK_SET); free (ptr); return(pos); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "spc") OR nolex THEN
	WRITELN "char *__b2c__spc(int amount) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], amount+1);" TO g_FUNCTIONS
	WRITELN "memset(buf[idx], 32, amount); __b2c__SETLEN(buf[idx], amount); buf[idx][amount] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "str") OR nolex THEN
	WRITELN "char * __b2c__str(double nr) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; int len; idx++; if (idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc (buf[idx], ", g_MAX_DIGITS, "); if(floor(nr) == nr)" TO g_FUNCTIONS
	WRITELN "{ len = snprintf(buf[idx], ", g_MAX_DIGITS, ", \"%ld\", (long)nr); } else { len = snprintf(buf[idx], ", g_MAX_DIGITS, ", \"%g\", (double)nr); } __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "sum") OR nolex THEN
	WRITELN "long __b2c__sum(int base, long *array, long nr, ...) { va_list ap; long limit = 0, total = 0; int x; va_start (ap, nr); limit = va_arg (ap, long); va_end (ap);" TO g_FUNCTIONS
	WRITELN "for(x = base; x < nr+base; x++) { if(limit == LONG_MAX){ total += array[x]; } else { if(array[x]>limit) { total += array[x]; } } } return(total); }" TO g_FUNCTIONS
	WRITELN "double __b2c__sumf(int base, double *array, double nr, ...) { va_list ap; double limit = 0, total = 0; int x; va_start (ap, nr); limit = va_arg (ap, double); va_end (ap);" TO g_FUNCTIONS
	WRITELN "for(x = base; x < nr+base; x++) { if(limit == DBL_MAX){ total += array[x]; } else { if(array[x]>limit) { total += array[x]; } } } return(total); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "tab") OR nolex THEN
	WRITELN "char *__b2c__tab(int amount) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], amount+1);" TO g_FUNCTIONS
	WRITELN "memset(buf[idx], 9, amount); __b2c__SETLEN(buf[idx], amount); buf[idx][amount] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "tally") OR nolex THEN
	WRITELN "long __b2c__tally(char *haystack, char *needle, int pos) { char *res; long total = 0; if (haystack == NULL) { return (0); }" TO g_FUNCTIONS
	WRITELN "if (needle == NULL || __b2c__len(needle) == 0) { return (0); } if (pos <= 0) { pos = 1; }" TO g_FUNCTIONS
	WRITELN "haystack+=pos-1; while((res = strstr(haystack, needle)) != NULL) { haystack = res+1; total++; } return((long)total); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "chrono") OR nolex THEN
	WRITELN "long __b2c__time (time_t now, int which){ long result; char *buffer; struct tm *ts; buffer = (char*)calloc(", g_MAX_DIGITS, ", sizeof (char)); ts = localtime (&now); switch (which) {" TO g_FUNCTIONS
	WRITELN "case 1: strftime (buffer, ", g_MAX_DIGITS, ", \"%d\", ts); break; case 2: strftime (buffer, ", g_MAX_DIGITS, ", \"%m\", ts); break; case 3: strftime (buffer, ", g_MAX_DIGITS, ", \"%Y\", ts); break;" TO g_FUNCTIONS
	WRITELN "case 4: strftime (buffer, ", g_MAX_DIGITS, ", \"%H\", ts); break; case 5: strftime (buffer, ", g_MAX_DIGITS, ", \"%M\", ts); break; case 6: strftime (buffer, ", g_MAX_DIGITS, ", \"%S\", ts); break;" TO g_FUNCTIONS
	WRITELN "case 7: strftime (buffer, ", g_MAX_DIGITS, ", \"%W\", ts); break; } result = atol(buffer); free(buffer); return(result); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "timer") OR nolex THEN
	WRITELN "unsigned long __b2c__timer(int init) { struct timeval time; static time_t elapsed_secs = 0; static int elapsed_usecs = 0; if(init) { gettimeofday(&time, NULL); elapsed_usecs = time.tv_usec; elapsed_secs = time.tv_sec; return(0); }" TO g_FUNCTIONS
	WRITELN "else { gettimeofday(&time, NULL); if(difftime(time.tv_sec, elapsed_secs) < 1) { return((unsigned long) (time.tv_usec-elapsed_usecs)/1000); }" TO g_FUNCTIONS
	WRITELN "else { return((unsigned long) (difftime(time.tv_sec, elapsed_secs)-1)*1000+((1000000-elapsed_usecs)+time.tv_usec)/1000); } } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "delimengine") OR nolex THEN
	WRITELN "long __b2c__delim_engine(int type, long *returned_value, char* string, char* delim, long nr) { long x, len, cnt = 0, start = 0; int in_string = 0, is_escaped = 0;" TO g_FUNCTIONS
	WRITELN "if (delim == NULL) { delim = __b2c__option_delim; } len = __b2c__len(delim); for (x = 0; string != NULL && string[x] != 0; x++) { if(!in_string) { if(len == 1 ? string[x] == delim[0] : !strncmp(string+x, delim, len))" TO g_FUNCTIONS
	WRITELN "{ if (__b2c__collapse == 0) { cnt++; } else if (x + len - start > len) { cnt++; } if (nr && nr == cnt) { break; } else { start = x + len; } } } if(string[x] == __b2c__option_esc) {if (!is_escaped) { is_escaped = 1; } else" TO g_FUNCTIONS
	WRITELN "{ is_escaped = 0; } } else if(string[x] == __b2c__option_dq) {if (!is_escaped && __b2c__option_quoted) { in_string = 1 - in_string; } is_escaped = 0; } else { is_escaped = 0; } } switch(type)" TO g_FUNCTIONS
	WRITELN "{ case 1: if(nr-cnt > 1) { *returned_value = 0; } else { *returned_value = x-start; } break; case 2: if(x==0) { *returned_value = 0; } else { if(__b2c__collapse==0) { cnt++; } else if(x+len-start>len){ cnt++; } *returned_value = cnt; } break; default: *returned_value = 0; } return(start); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "argument") OR nolex THEN
	WRITELN "void __b2c__argument(char **arg, int total, char **data) { long x, dlen, slen, pos, tot_len = 0; char quote[] = { 34, 0 }; if (total == 0) { *arg = NULL; } else { dlen = __b2c__len (__b2c__option_delim); for (pos = 0; pos < total; pos++)" TO g_FUNCTIONS
	WRITELN "{ slen = strlen(data[pos]); *arg = (char *) realloc (*arg, tot_len + slen * 2 + dlen + 1); if (strstr (data[pos], \" \") || strstr (data[pos], \"\\\"\")) { (*arg)[tot_len++] = 34; for (x = 0; data[pos][x] != 0; x++) { if (data[pos][x] == quote[0])" TO g_FUNCTIONS
	WRITELN "{ (*arg)[tot_len++] = __b2c__option_esc; } (*arg)[tot_len++] = data[pos][x]; } (*arg)[tot_len++] = 34; } else { memmove (*arg + tot_len, data[pos], slen); tot_len += slen; } if (pos < total - 1) { memmove (*arg + tot_len, __b2c__option_delim, dlen);" TO g_FUNCTIONS
	WRITELN "tot_len += dlen; } } *(*arg + tot_len) = '\\0'; } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "token") OR nolex THEN
	WRITELN "char *__b2c__token(char *string, long nr, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start; long length = 0; if (string == NULL || nr < 1) { return (EmptyString); }" TO g_FUNCTIONS
	WRITELN "start = __b2c__delim_engine(1, &length, string, delim, nr); if(length == 0) { return(EmptyString); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], length+1); memmove(buf[idx], string + start, length); __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "amount") OR nolex THEN
	WRITELN "long __b2c__amount(char *string, char *delim) { long amount = 0; if (string == NULL) { return (0); } __b2c__delim_engine(2, &amount, string, delim, 0); return(amount); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "hasdelim") OR nolex THEN
	WRITELN "int __b2c__hasdelim (char *string, char *delim) { long length = 0; long start = 0; if (string == NULL) { return (0); }" TO g_FUNCTIONS
	WRITELN "start = __b2c__delim_engine (2, &length, string, delim, 2); if(start == 0) { return (0); } if (delim == NULL) { delim = __b2c__option_delim; } return (start-__b2c__len (delim)+1); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "exchange") OR nolex THEN
	WRITELN "char *__b2c__exchange (char *string, int index1, int index2, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long tmp, tlen, len1, len2, start1 = 0, start2 = 0; long length = 0;" TO g_FUNCTIONS
	WRITELN "if (string == NULL || index1 <= 0 || index2 <= 0) { return (string); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start1 = __b2c__delim_engine(1, &length, string, delim, index1);" TO g_FUNCTIONS
	WRITELN "len1 = length; length = 0; start2 = __b2c__delim_engine(1, &length, string, delim, index2); len2 = length; if (start1 == start2) { return (string); } else if (start2 < start1)" TO g_FUNCTIONS
	WRITELN "{ tmp = start2; start2 = start1; start1 = tmp; tmp = len2; len2 = len1; len1 = tmp; } tlen = __b2c__len (string); buf[idx] = (char*)__b2c_str_realloc(buf[idx], tlen+1); memmove(buf[idx], string, start1);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + start1, string + start2, len2); memmove(buf[idx] + start1 + len2, string + start1 + len1, start2 - (start1 + len1));" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + start1 + len2 + start2 - (start1 + len1), string + start1, len1); memmove(buf[idx] + start1 + len2 + start2 - (start1 + len1) + len1, string + start2 + len2, tlen - (start2 + len2));" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], tlen); buf[idx][tlen] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "change") OR nolex THEN
	WRITELN "char *__b2c__change(char *string, int index, char *cnew, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long tlen, start, len, nlen; long length = 0; if (string == NULL || index <= 0)" TO g_FUNCTIONS
	WRITELN "{ return (string); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine(1, &length, string, delim, index); len = length; tlen = __b2c__len(string); nlen = __b2c__len(cnew);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], tlen-len+nlen+1); memmove(buf[idx], string, start); memmove(buf[idx] + start, cnew, nlen); memmove(buf[idx] + start + nlen, string + start + len, tlen - (start + len));" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], tlen - len + nlen); buf[idx][tlen-len+nlen] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "istok") OR nolex THEN
	WRITELN "long __b2c__istoken(char *string, char *token, char *delim) { long len, dlen, start, x, result = 0; long length = 0, amount = 0; if(string == NULL) { return(0); } if(delim == NULL)" TO g_FUNCTIONS
	WRITELN "{ delim = __b2c__option_delim; } len = __b2c__len(token); if(len==0) { return(0); } dlen = __b2c__len(delim); start = __b2c__delim_engine (2, &amount, string, delim, 0); for(x = 0; x < amount; x++)" TO g_FUNCTIONS
	WRITELN "{ start = __b2c__delim_engine (1, &length, string, delim, 1); if(len == length && memcmp(string + start, token, len) == 0) { result = x+1; break; } string += (start + length + dlen); } return (result); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "uniq") OR nolex THEN
	WRITELN "char *__b2c__uniq (char *string, char *delim) { long x, dlen, start, amount = 0, length = 0; int t = 1; __b2c__htable *table; char *item, *result; unsigned short pos; if(string == NULL) { return (string); }" TO g_FUNCTIONS
	WRITELN "if(delim == NULL) { delim = __b2c__option_delim; } dlen = __b2c__len (delim); start = __b2c__delim_engine (2, &amount, string, delim, 0); if(amount <= 1) { return (string); }" TO g_FUNCTIONS
	WRITELN "table = __b2c__hash_new(); for (x = 0; x < amount; x++) { start = __b2c__delim_engine (1, &length, string, delim, 1); item = __b2c__strndup(string+start, length); pos = __b2c__HashFNV1a_16(item);" TO g_FUNCTIONS
	WRITELN "if(!__b2c__hash_find_key(table, pos, item)) { __b2c__hash_add(table, &t, item); } free(item); string += (start + length + dlen); } result = __b2c__hash_obtain(table, delim);" TO g_FUNCTIONS
	WRITELN "__b2c__hash_clear(table); free(table); return(result); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "sortdelim") OR nolex THEN
	WRITELN "char *__b2c__sort(char *string, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char **array; char *buffer, *backup; long start, total = 0, x, len, dlen; long amount = 0; long length = 0;" TO g_FUNCTIONS
	WRITELN "if(string == NULL) { return (string); } if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } dlen = __b2c__len (delim); buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len(string)+1);" TO g_FUNCTIONS
	WRITELN "buffer = __b2c__strdup (string); backup = buffer; start = __b2c__delim_engine (2, &amount, buffer, delim, 0); array = (char **) calloc(amount, sizeof (char *)); for (x = 0; x < amount; x++)" TO g_FUNCTIONS
	WRITELN "{ start = __b2c__delim_engine (1, &length, string, delim, 1); buffer[start + length] = '\\0'; if(buffer[start] == 34 && buffer[start+length-1] == 34) { buffer[start + length-1] = '\\0';" TO g_FUNCTIONS
	WRITELN "array[x] = buffer + start + 1; } else { array[x] = buffer + start; } string += (start + length + dlen); buffer += (start + length + dlen); } qsort (&array[0], amount, sizeof (char *), __b2c__sortstr);" TO g_FUNCTIONS
	WRITELN "for (x = 0; x < amount; x++) { len = strlen (array[x]); if(strstr(array[x], delim)) { buf[idx][total] = 34; memmove(buf[idx] + total+1, array[x], len);" TO g_FUNCTIONS
	WRITELN "buf[idx][total+len+1] = 34; total += len+2;} else { memmove(buf[idx] + total, array[x], len); total += len; } if (x < amount - 1) { memmove(buf[idx] + total, delim, dlen);" TO g_FUNCTIONS
	WRITELN "total += dlen; } } free (backup); free (array); __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "revstr") OR nolex THEN
	WRITELN "char *__b2c__rev(char *string, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, total, x, len, dlen; long amount = 0; long length = 0; if (string == NULL) { return (string); }" TO g_FUNCTIONS
	WRITELN "len = __b2c__len (string); if (delim == NULL) { delim = __b2c__option_delim; } dlen = __b2c__len (delim); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, delim, 0);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], len + 1); total = len; for (x = 0; x < amount; x++) { start = __b2c__delim_engine (1, &length, string, delim, 1);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + total-length, string + start, length); total -= length; if (x < amount-1) { memmove(buf[idx] + total-dlen, delim, dlen); total -= dlen; }" TO g_FUNCTIONS
	WRITELN "string += (start + length + dlen); } __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "delimstr") OR nolex THEN
	WRITELN "char *__b2c__delim(char *string, char *from, char *to) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, total = 0, x, tlen, dlen; long amount = 0; long length = 0; if (string == NULL) { return (string); }" TO g_FUNCTIONS
	WRITELN "if(from == NULL) { from = __b2c__option_delim; } if(to == NULL) { to = __b2c__option_delim; } dlen = __b2c__len (from); tlen = __b2c__len (to); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, from, 0);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len(string)+amount*tlen+1); for (x = 0; x < amount; x++) { start = __b2c__delim_engine (1, &length, string, from, 1); memmove(buf[idx] + total, string + start, length);" TO g_FUNCTIONS
	WRITELN "total += length; if (x < amount-1) { memmove(buf[idx] + total, to, tlen); total += tlen; } string += (start + length + dlen); } __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "head") OR nolex THEN
	WRITELN "char *__b2c__head (char *string, long pos, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start; long amount = 0; long length = 0; if (string == NULL)" TO g_FUNCTIONS
	WRITELN "{ return (string); } if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, delim, 0);" TO g_FUNCTIONS
	WRITELN "if(amount < 1 || pos < 1) { return (EmptyString); } if (pos > amount) { pos = amount; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len(string)+1); start = __b2c__delim_engine (1, &length, string, delim, pos);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx], string, start + length); __b2c__SETLEN(buf[idx], start + length); buf[idx][start + length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "tail") OR nolex THEN
	WRITELN "char *__b2c__tail(char *string, long pos, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, slen; long amount = 0; long length = 0; if (string == NULL)" TO g_FUNCTIONS
	WRITELN "{ return (string); } if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, delim, 0);" TO g_FUNCTIONS
	WRITELN "if (amount < 1 || pos < 1) { return (EmptyString); } if (amount - pos + 1 < 1) { pos = 1; } else { pos = amount - pos + 1; } slen = __b2c__len (string); buf[idx] = (char*)__b2c_str_realloc(buf[idx], slen+1);" TO g_FUNCTIONS
	WRITELN "start = __b2c__delim_engine(1, &length, string, delim, pos); memmove(buf[idx], string + start, slen-start); __b2c__SETLEN(buf[idx], slen-start); buf[idx][slen-start] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "append") OR nolex THEN
	WRITELN "char *__b2c__append (char *string, long pos, char *cnew, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, dlen, slen, nlen, total = 0; long amount = 0; long length = 0; if (cnew == NULL || pos < 0) { return (string); }" TO g_FUNCTIONS
	WRITELN "if (string == NULL) { string = EmptyString; } if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, delim, 0); dlen = __b2c__len (delim); nlen = __b2c__len (cnew); slen = __b2c__len (string);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], slen + nlen + dlen + 1); if(pos == 0 || pos > amount) { if(!(__b2c__collapse == 1 && slen == 0)) { memmove(buf[idx], string, slen); total += slen; if(!((slen == (amount-1) * dlen && nlen > 0) || (slen == 0 && nlen > 0)))" TO g_FUNCTIONS
	WRITELN "{ memmove(buf[idx] + total, delim, dlen); total += dlen; } } memmove(buf[idx] + total, cnew, nlen); total += nlen; } else { start = __b2c__delim_engine (1, &length, string, delim, pos); memmove(buf[idx], string, start); total += start;" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + total, cnew, nlen); total += nlen; memmove(buf[idx] + total, delim, dlen); total += dlen; memmove(buf[idx] + total, string + start, slen - start); total += (slen - start); }" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "delstr") OR nolex THEN
	WRITELN "char *__b2c__del(char *string, long pos, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, slen, dlen, total = 0; long amount = 0; long length = 0; if (string == NULL)" TO g_FUNCTIONS
	WRITELN "{ return (string); } if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, delim, 0); if (pos < 1 || pos > amount)" TO g_FUNCTIONS
	WRITELN "{ return(string); } dlen = __b2c__len (delim); slen = __b2c__len (string); buf[idx] = (char*)__b2c_str_realloc(buf[idx], slen + 1); start = __b2c__delim_engine (1, &length, string, delim, pos); memmove(buf[idx], string, start);" TO g_FUNCTIONS
	WRITELN "total += start; if (pos < amount) { memmove(buf[idx] + total, string + start + length + dlen, slen-(start + length + dlen)); total += slen-(start + length + dlen); }" TO g_FUNCTIONS
	WRITELN "else if(total >= dlen) { total -= dlen; } __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "cut") OR nolex THEN
	WRITELN "char *__b2c__cut(char *string, long pos1, long pos2, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start1, start2, tmp, total = 0; long amount = 0; long length = 0; if (string == NULL)" TO g_FUNCTIONS
	WRITELN "{ return (string); } if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } if (pos1 > pos2) { tmp = pos1; pos1 = pos2; pos2 = tmp; } __b2c__delim_engine (2, &amount, string, delim, 0);" TO g_FUNCTIONS
	WRITELN "if(pos1 < 1) { pos1 = 1; } if(pos2 > amount) { pos2 = amount; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len(string)+1); start1 = __b2c__delim_engine (1, &length, string, delim, pos1);" TO g_FUNCTIONS
	WRITELN "start2 = __b2c__delim_engine (1, &length, string, delim, pos2); memmove(buf[idx], string + start1, start2-start1+length); total += (start2-start1+length); __b2c__SETLEN(buf[idx], total);" TO g_FUNCTIONS
	WRITELN "buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "align") OR nolex THEN
	WRITELN "char *__b2c__align(int l, char *k, char *str, unsigned long width, int mode, int indent) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, dlen, x, y, left, line_start = 0, last_write_pos, write_pos = 0, characters, last_read_pos, read_pos = 0, wtotal = 0, ctotal = 0, found = 0, tab, pos, cursor;" TO g_FUNCTIONS
	WRITELN "int quoted, collapse; long amount = 0; long total[1] = { 0 }; long length = 0; long lw[1] = { 0 }; char *string, *backup, *concat, *wrap, *line; if (str == NULL) { return (str); } if (width < 1) { return (EmptyString); }" TO g_FUNCTIONS
	WRITELN "quoted = __b2c__option_quoted; __b2c__option_quoted = 0; string = __b2c__strdup(str); backup = string; for (x = 0; string[x]; x++) { if (string[x] == 10 && string[x + 1] == 10) x++; else if (string[x] == 10) string[x] = 32; } x--;" TO g_FUNCTIONS
	WRITELN "while (x >= 0 && string[x] == 32) { string[x] = 0; x--; } dlen = __b2c__len(__b2c__option_delim); start = __b2c__delim_engine (2, &amount, string, NULL, 0); concat = (char *) calloc (x + amount + 1, sizeof (char)); for (x = 0; x < amount; x++) { start = __b2c__delim_engine (1, &length, string, NULL, 1);" TO g_FUNCTIONS
	WRITELN "memmove (concat + ctotal, string + start, length); ctotal += length; if (x < amount) { memset (concat + ctotal, 32, 1); ctotal += 1; } string += (start + length + dlen); } free(backup); wrap = (char *) calloc (ctotal + ctotal / width + 1, sizeof (char)); backup = wrap; while (read_pos < ctotal)" TO g_FUNCTIONS
	WRITELN "{ if (*(concat + read_pos) == 32) { if (write_pos == 0) { read_pos++; continue; } else { last_write_pos = wtotal; last_read_pos = read_pos; found = 1; } } memmove (wrap + wtotal, concat + read_pos, 1); write_pos++; wtotal++; if (*(concat + read_pos) == 10)" TO g_FUNCTIONS
	WRITELN "{ write_pos = 0; line_start = wtotal; } else if ( (__b2c__option_utf8 ? __b2c__ucs2_clen (l, k, \"ALIGN$\", wrap + line_start, write_pos) : write_pos) >= width) { if (found) { memset (wrap + last_write_pos, 10, 1); wtotal = last_write_pos + 1; read_pos = last_read_pos; if (*(concat + read_pos + 1) == 10)" TO g_FUNCTIONS
	WRITELN "{ read_pos++; } } else { memset (wrap + wtotal, 10, 1); wtotal += 1; } found = 0; write_pos = 0; line_start = wtotal; } read_pos++; } collapse = __b2c__collapse; __b2c__collapse = 0; start = __b2c__delim_engine (2, &amount, wrap, \"\\n\", 0); __b2c__collapse = collapse;" TO g_FUNCTIONS
	WRITELN "line_start = 0; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], amount * indent + amount * width * 4 + 1); line = (char *) calloc (width * 4, sizeof (char)); for (x = 1; x <= amount; x++) { collapse = __b2c__collapse; __b2c__collapse = 0; start = __b2c__delim_engine (1, &length, wrap, \"\\n\", 1);" TO g_FUNCTIONS
	WRITELN "while (*(wrap + start + length) == 32) { length--; } characters = (__b2c__option_utf8 ? __b2c__ucs2_clen (l, k, \"ALIGN$\", wrap + start, length) : length); __b2c__collapse = collapse; switch (mode) { case 0: memset(buf[idx] + line_start, 32, indent); line_start += indent;" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + line_start, wrap + start, length); line_start += length; memset(buf[idx] + line_start, 32, width - characters); line_start += (width - characters); if (x < amount) { memset(buf[idx] + line_start, '\\n', 1);" TO g_FUNCTIONS
	WRITELN "line_start++; } break; case 1: memset(buf[idx] + line_start, 32, indent); line_start += indent; memset(buf[idx] + line_start, 32, width - characters); line_start += (width - characters); memmove(buf[idx] + line_start, wrap + start, length);" TO g_FUNCTIONS
	WRITELN "line_start += length; if (x < amount) { memset(buf[idx] + line_start, '\\n', 1); line_start++; } break; case 2: tab = (width - characters) / 2; memset(buf[idx] + line_start, 32, indent + tab); line_start += (indent + tab);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + line_start, wrap + start, length); line_start += length; memset(buf[idx] + line_start, 32, tab + (width - characters) % 2); line_start += (tab + (width - characters) % 2); if (x < amount)" TO g_FUNCTIONS
	WRITELN "{ memset(buf[idx] + line_start, '\\n', 1); line_start++; } break; case 3: memset(buf[idx] + line_start, 32, indent); line_start += indent; memset (line, 0, width * 4); memmove (line, wrap + start, length); pos = __b2c__delim_engine (2, total, line, NULL, 0);" TO g_FUNCTIONS
	WRITELN "if (total[0] == 0) { total[0] = 1; } cursor = 0; left = width - characters; for (y = 1; y <= total[0]; y++) { pos = __b2c__delim_engine (1, lw, line, NULL, y); memmove(buf[idx] + line_start + cursor, line + pos, lw[0]); cursor += lw[0]; if (left >= width/4)" TO g_FUNCTIONS
	WRITELN "{ if (y < total[0]) { tab = 1; } else { tab = left; } } else if (total[0] > 1) { tab = 1 + left / (total[0] - 1); if (left % (total[0] - 1)) { tab++; left--; } } else { tab = left; } if ((__b2c__option_utf8 ? __b2c__ucs2_clen (l, k, \"ALIGN$\", buf[idx] + line_start, cursor) : cursor) < width)" TO g_FUNCTIONS
	WRITELN "{ memset(buf[idx] + line_start + cursor, 32, tab); cursor += tab; } } line_start += cursor; if (x < amount) { memset(buf[idx] + line_start, '\\n', 1); line_start++; } break; } wrap += (start + length + 1); } free (backup); free (concat); free (line);" TO g_FUNCTIONS
	WRITELN "__b2c__option_quoted = quoted; __b2c__SETLEN(buf[idx], line_start); buf[idx][line_start] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "proper") OR nolex THEN
	WRITELN "char * __b2c__proper(int l, char *k, char *string, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char *local; long start, total = 0, x, y, dlen, blen; long amount = 0; long length = 0; wchar_t wcs[8] = { 0 }; if (string == NULL) { return (string); }" TO g_FUNCTIONS
	WRITELN "if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } dlen = __b2c__len (delim); start = __b2c__delim_engine (2, &amount, string, delim, 0); buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len (string)+1); if(__b2c__option_utf8)" TO g_FUNCTIONS
	WRITELN "{ local = setlocale (LC_ALL, \"\"); for (x = 0; x < amount; x++) { start = __b2c__delim_engine (1, &length, string, delim, 1); blen = __b2c__blen (l, k, \"PROPER$\", string + start, 1, 0); if (mbtowc (wcs, string + start, blen) == (int) - 1) { ERROR = 38; RUNTIMEFERR (\"PROPER$\", ERROR, k, l); }" TO g_FUNCTIONS
	WRITELN "*wcs = towupper (*wcs); if (wctomb(buf[idx] + total, *wcs) == (int) - 1) { ERROR = 38; RUNTIMEFERR (\"PROPER$\", ERROR, k, l); } for (y = blen; y < length; y += blen) { blen = __b2c__blen (l, k, \"PROPER$\", string + start + y, 1, 0); if (mbtowc (wcs, string + start + y, blen) == (int) - 1)" TO g_FUNCTIONS
	WRITELN "{ ERROR = 38; RUNTIMEFERR (\"PROPER$\", ERROR, k, l); } if(__b2c__option_proper == 0) { *wcs = towlower (*wcs); } if (wctomb(buf[idx] + total + y, *wcs) == (int) - 1) { ERROR = 38; RUNTIMEFERR (\"PROPER$\", ERROR, k, l); } } total += length; if (x < amount-1) { memmove(buf[idx] + total, delim, dlen);" TO g_FUNCTIONS
	WRITELN "total += dlen; } string += (start + length + dlen); } setlocale (LC_ALL, local); } else { for (x = 0; x < amount; x++) { start = __b2c__delim_engine (1, &length, string, delim, 1); *(buf[idx] + total) = toupper(*(string+start)); for (y = 1; y < length; y ++) { *(buf[idx]+total+y) = (__b2c__option_proper == 0 ? tolower(*(string+start+y)) : *(string+start+y)); } " TO g_FUNCTIONS
	WRITELN "total += length; if (x < amount-1) { memmove(buf[idx] + total, delim, dlen); total += dlen; } string += (start + length + dlen); } } __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "rotate") OR nolex THEN
	WRITELN "char *__b2c__rotate (char *string, int pos, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, total = 0, x, dlen; long amount = 0, length = 0; char *next; if (string == NULL) { return (string); } if (delim == NULL) { delim = __b2c__option_delim; }" TO g_FUNCTIONS
	WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } dlen = __b2c__len (delim); start = __b2c__delim_engine (2, &amount, string, delim, 0); if (amount <= 1) { return (string); } if (abs (pos) >= amount) { pos = pos % amount; } if (pos == 0) { return (string); } if (pos < 0)" TO g_FUNCTIONS
	WRITELN "{ pos = amount + pos; } next = string; buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len (string) + 1); start = __b2c__delim_engine (1, &length, string, delim, amount-pos+1); string += start; for (x = amount - pos; x < amount; x++) { start = __b2c__delim_engine (1, &length, string, delim, 1);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + total, string + start, length); total += length; memmove(buf[idx] + total, delim, dlen); total += dlen; string += (start + length + dlen); } for (x = 0; x < amount - pos; x++) { start = __b2c__delim_engine (1, &length, next, delim, 1);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx] + total, next + start, length); total += length; if (x < amount - pos - 1) { memmove(buf[idx] + total, delim, dlen); total += dlen; } next += (start + length + dlen); }" TO g_FUNCTIONS
	WRITELN "__b2c__SETLEN(buf[idx], total);buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "last") OR nolex THEN
	WRITELN "char *__b2c__last (char *string, int pos, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, slen; long amount = 0; long length = 0; if (string == NULL) { return (string); } if (delim == NULL) { delim = __b2c__option_delim; }" TO g_FUNCTIONS
	WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, delim, 0); if (pos <= 0) { return (string); } if (amount < 1 || pos >= amount) { return (EmptyString); } slen = __b2c__len (string); buf[idx] = (char*)__b2c_str_realloc(buf[idx], slen + 1);" TO g_FUNCTIONS
	WRITELN "start = __b2c__delim_engine (1, &length, string, delim, pos+1); memmove(buf[idx], string + start, slen-start); __b2c__SETLEN(buf[idx], slen-start); buf[idx][slen-start] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "first") OR nolex THEN
	WRITELN "char * __b2c__first (char *string, int pos, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long dlen, end; long amount = 0; long length = 0; if (string == NULL) { return (string); } if (delim == NULL) { delim = __b2c__option_delim; }" TO g_FUNCTIONS
	WRITELN "idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } end = __b2c__delim_engine (2, &amount, string, delim, 0); if (pos <= 0) { return (string); } if (amount < 1 || pos >= amount) { return (EmptyString); } buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len(string)+1);" TO g_FUNCTIONS
	WRITELN "end = __b2c__delim_engine (1, &length, string, delim, amount-pos+1); dlen = __b2c__len (delim); memmove(buf[idx], string, end-dlen); __b2c__SETLEN(buf[idx], end-dlen); buf[idx][end-dlen] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "match") OR nolex THEN
	WRITELN "int __b2c__match(char *string1, char *string2, long count, char *delim) { long dlen, start1, start2, amount1, amount2, length1, length2, tmplen; int x, found = 1, wildcard = 0, after = 0; if (string1 == NULL && string2 == NULL) { return (1); }" TO g_FUNCTIONS
	WRITELN "if (count == 0) { return (1); } if (delim == NULL) { delim = __b2c__option_delim; } start1 = __b2c__delim_engine (2, &amount1, string1, delim, 0); if (count > amount1) { return (0); } if(count == -1) { count = amount1; } dlen = __b2c__len (delim);" TO g_FUNCTIONS
	WRITELN "for (x = 0; x < count; x++) { start1 = __b2c__delim_engine (1, &length1, string1, delim, 1); start2 = __b2c__delim_engine (1, &length2, string2, delim, 1); if (length1 == 0) { found = wildcard; break; } if (length2 == 0)" TO g_FUNCTIONS
	WRITELN "{ found = wildcard; break; } if (strncmp (string2, \"?\", 1)) { if (!strncmp (string2, \"*\", 1)) { wildcard = 1; __b2c__delim_engine (2, &amount2, string2+1, delim, 0); if(amount2) { after = 1; string2+=1+dlen; } else { after = 0; found = wildcard; break; } }" TO g_FUNCTIONS
	WRITELN "else if (!strncmp (string2, \"\\\\?\", 2) || !strncmp (string2, \"\\\\*\", 2)) { string2++; length2--; } __b2c__delim_engine (1, &tmplen, string2, delim, 1); if(length1 != tmplen || memcmp (string1, string2, tmplen)) { if (wildcard == 0) { found = 0; break; } else { string2 = string2-1-dlen; } }" TO g_FUNCTIONS
	WRITELN "else { wildcard = 0; after = 0; } if(wildcard == 0) { string2 += (start2 + length1 + dlen); } } else { string2 += (start2 + length2 + dlen); } string1 += (start1 + length1 + dlen); } if(after) { found = 0; } return (found); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "explode") OR nolex THEN
	WRITELN "char *__b2c__explode (int l, char *k, char *string, int pos, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long x, dlen, len, blen, ctr=0, where = 0, escaped = 0, in_string = 0; if (string == NULL || pos <= 0 || pos >= (len = __b2c__len (string)) ) { return (string); } if (delim == NULL) { delim = __b2c__option_delim; }" TO g_FUNCTIONS
	WRITELN "dlen = __b2c__len (delim); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } blen = pos; buf[idx] = (char*)__b2c_str_realloc(buf[idx], len + (len - 1) * dlen + 1); for (x = 0; x < len; x += blen) { if (__b2c__option_utf8) { blen = __b2c__blen(l, k, \"EXPLODE$\", string + x, pos, 0); } if(*(string+x) == __b2c__option_esc) { escaped = 1 - escaped; } if(*(string+x) == 34)" TO g_FUNCTIONS
	WRITELN "{ if(!escaped && __b2c__option_quoted) { in_string = 1 - in_string; } escaped = 0; } else { escaped = 0; } memmove(buf[idx] + where, string + x, blen); where+=blen; if (x < (len - blen) && !in_string) { memmove(buf[idx] + where, delim, dlen); where+=dlen; ctr+=dlen; } } __b2c__SETLEN(buf[idx], len+ctr); buf[idx][len+ctr] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "merge") OR nolex THEN
	WRITELN "char *__b2c__merge(char *string, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, total = 0, x; long amount = 0; long length = 0; if (string == NULL) { return (string); }" TO g_FUNCTIONS
	WRITELN "if (delim == NULL) { delim = __b2c__option_delim; } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &amount, string, delim, 0); buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len (string) + 1); for(x = 1; x <= amount; x++)" TO g_FUNCTIONS
	WRITELN "{ start = __b2c__delim_engine (1, &length, string, delim, x); memmove(buf[idx] + total, string + start, length); total += length; } __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "between") OR nolex THEN
	WRITELN "char *__b2c__inbetween(int flag, char *haystack, char *lm, char *rm, int greedy) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char *l, *pos; int collapse; long len, start, end=0, in, w1, w2; long length = 0;" TO g_FUNCTIONS
	WRITELN "if (haystack == NULL || lm == NULL || rm == NULL) { return (EmptyString); } collapse = __b2c__collapse; __b2c__collapse = 0; idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } start = __b2c__delim_engine (2, &length, haystack, lm, 2);" TO g_FUNCTIONS
	WRITELN "if (start == 0) { __b2c__collapse = collapse; return (EmptyString); } if (greedy == 0) { in = __b2c__delim_engine (2, &length, haystack+start+end, rm, 2); if (in == 0) { __b2c__collapse = collapse; return (EmptyString); }" TO g_FUNCTIONS
	WRITELN "l = haystack+start-__b2c__len(lm); pos = haystack+start+in-__b2c__len(rm); } else if (greedy == 1) { while (1) { in = __b2c__delim_engine (2, &length, haystack+start+end, rm, 2); if(in) { end += in; } else { break; } }" TO g_FUNCTIONS
	WRITELN "if (end == 0) { __b2c__collapse = collapse; return (EmptyString); } l = haystack+start-__b2c__len(lm); pos = haystack+start+end-__b2c__len(rm); } else { w1 = start; w2 = start;" TO g_FUNCTIONS
	WRITELN "while (1) { end = __b2c__delim_engine (2, &length, haystack + w1, rm, 2); if (end == 0) { __b2c__collapse = collapse; return (EmptyString); } in = __b2c__delim_engine (2, &length, haystack + w2, lm, 2); if (in && ((w2 + in) < (w1 + end)))" TO g_FUNCTIONS
	WRITELN "{ w1 = w1 + end; w2 = w2 + in; } else { break; } } l = haystack + start - __b2c__len (lm); pos = haystack + w1 + end - __b2c__len (rm); } if (flag) { pos += strlen (rm); len = strlen (pos); buf[idx] = (char*)__b2c_str_realloc(buf[idx], (l - haystack) + len + 1);" TO g_FUNCTIONS
	WRITELN "memmove(buf[idx], haystack, l - haystack); memmove(buf[idx] + (l - haystack), pos, len); __b2c__SETLEN(buf[idx], (l - haystack) + len); buf[idx][(l - haystack) + len] = '\\0'; } else" TO g_FUNCTIONS
	WRITELN "{ l += strlen (lm); buf[idx] = (char*)__b2c_str_realloc(buf[idx], pos - l + 1); memmove(buf[idx], l, pos - l); __b2c__SETLEN(buf[idx], pos - l); buf[idx][pos - l] = '\\0'; } __b2c__collapse = collapse; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "ucase") OR nolex THEN
	WRITELN "char * __b2c__ucase(int l, char *k, char *src) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long len, i; size_t mbslen; wchar_t *wcs, *wp; char *local; if (src == NULL) { return (NULL); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } len = __b2c__len (src);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], len + 1); if(__b2c__option_utf8) { local = setlocale (LC_ALL, \"\"); if ((mbslen = mbstowcs (NULL, src, 0)) == (size_t) - 1) { ERROR = 38; RUNTIMEFERR (\"UCASE$\", ERROR, k, l); } wcs = (wchar_t*)calloc (mbslen + 1, sizeof (wchar_t)); if (mbstowcs (wcs, src, mbslen + 1) == (size_t) - 1)" TO g_FUNCTIONS
	WRITELN "{ ERROR = 38; RUNTIMEFERR (\"UCASE$\", ERROR, k, l); } for (wp = wcs; *wp != 0; wp++) { *wp = towupper (*wp); } if(wcstombs(buf[idx], wcs, len) == (size_t) - 1) { ERROR = 38; RUNTIMEFERR (\"UCASE$\", ERROR, k, l); } free (wcs);" TO g_FUNCTIONS
	WRITELN "setlocale(LC_ALL, local); } else { for (i = 0; i < len; i++) { buf[idx][i] = toupper (src[i]); } } __b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "utf8") OR nolex THEN
	WRITELN "int __b2c_utf8_conv(int txt, char* utf8) { unsigned char b1, b2, b3; int len; if (txt > 0xFFFF) { b1 = txt & 0x0000FF; b2 = (txt & 0x00FF00) >> 8; b3 = (txt & 0xFF0000) >> 16;" TO g_FUNCTIONS
	WRITELN "len = snprintf (utf8, 5, \"%c%c%c%c\", 0xF0 | (b3 >> 2), 0x80 | ((b3 & 0x03) << 4) | ((b2 & 0xF0) >> 4), 0x80 | ((b2 & 0x0F) << 2) | ((b1 & 0xC0) >> 6)," TO g_FUNCTIONS
	WRITELN "0x80 | (b1 & 0x3F)); } else if (txt > 0x07FF) { b1 = txt & 0x00FF; b2 = (txt & 0xFF00) >> 8; len = snprintf (utf8, 4, \"%c%c%c\", 0xE0 | ((b2 & 0xF0) >> 4)," TO g_FUNCTIONS
	WRITELN "0x80 | ((b2 & 0x0F) << 2) | ((b1 & 0xC0) >> 6), 0x80 | (b1 & 0x3F)); } else if (txt > 0x007F) { b1 = txt & 0x00FF; b2 = (txt & 0xFF00) >> 8; len = snprintf (utf8, 3, \"%c%c\"," TO g_FUNCTIONS
	WRITELN "0xC0 | (b2 << 2) | ((b1 & 0xC0) >> 6), 0x80 | (b1 & 0x3F)); } else { len = snprintf (utf8, 2, \"%c\", txt & 0x7F); } return(len); }" TO g_FUNCTIONS
	WRITELN "unsigned long __b2c__ulen (int l, char *k, char *func, char *ptr, int pos) { long len = 0; if (ptr == NULL) { return(0); } if(pos < 0) { while(*ptr){ if((*ptr&0xF0) == 0xF0) { len++; ptr += 4; } else if((*ptr&0xE0) == 0xE0) { len++; ptr += 3; }" TO g_FUNCTIONS
	WRITELN "else if((*ptr&0xC0) == 0xC0) { len++; ptr += 2; } else if((*ptr&0x80) == 0) { len++; ptr++; } else { ERROR = 38; RUNTIMEFERR(func, ERROR, k, l); } } } else { len = __b2c__ucs2_clen(l, k, \"ULEN\", ptr, pos); } return(len); }" TO g_FUNCTIONS
	WRITELN "unsigned long __b2c__blen (int l, char *k, char *func, char *ptr, long c, int flag) { char *org = ptr; if (ptr == NULL){ return (0); }" TO g_FUNCTIONS
	WRITELN "if(flag) { c = __b2c__ulen (l, k, \"BYTELEN\", org, -1)-c; } while (*ptr && c > 0) { if ((*ptr & 0xF0) == 0xF0) { ptr += 4; } else if ((*ptr & 0xE0) == 0xE0) { ptr += 3; } else if ((*ptr & 0xC0) == 0xC0) { ptr += 2; } else if ((*ptr & 0x80) == 0)" TO g_FUNCTIONS
	WRITELN "{ ptr++; } else { ERROR = 38; fprintf (stderr, \"Cannot decode UTF-8 string: '%s'\\n\", org); RUNTIMEFERR (func, ERROR, k, l); } c--; } if(flag) { return (__b2c__len(org) - (ptr - org)); } else { return (ptr - org); } }" TO g_FUNCTIONS
	WRITELN "unsigned long __b2c__ucs2_clen (int l, char* k, char *func, char *ptr, int c) { int len = 0; char *org; if (ptr == NULL) return (0); org = ptr; while (*ptr && c > 0) { if ((*ptr & 0xF0) == 0xF0) { ptr += 4; c -= 4; } else if ((*ptr & 0xE0) == 0xE0)" TO g_FUNCTIONS
	WRITELN "{ ptr += 3; c -= 3; } else if ((*ptr & 0xC0) == 0xC0) { ptr += 2; c -= 2; } else if ((*ptr & 0x80) == 0) { ptr++; c--; } else { ERROR = 38; fprintf(stderr, \"Cannot decode UTF-8 string: '%s'\\n\", org); RUNTIMEFERR (func, ERROR, k, l); } len++; } return (len); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "wait") OR nolex THEN
	WRITELN "long __b2c__netpeek(int l, char *k, uintptr_t fd, int usec){fd_set rfds; struct timeval tv; int desc; long retval; struct termios oldt = { 0}, newt = { 0 }; if(fd == STDIN_FILENO){tcgetattr(STDIN_FILENO, &oldt);" TO g_FUNCTIONS
	WRITELN "newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); newt.c_cc[VMIN]=1; newt.c_cc[VTIME]=0; tcsetattr(STDIN_FILENO, TCSANOW, &newt);} tv.tv_usec = (usec%1000)*1000; tv.tv_sec = usec/1000; FD_ZERO(&rfds);" TO g_FUNCTIONS
	WRITELN "if(fd == STDIN_FILENO) { desc = fd; } else {" TO g_FUNCTIONS
	IF g_OPTION_TLS THEN
		IF TALLY(g_LIB_TLS$, "gnutls") THEN
			WRITELN "if(__b2c__option_tls) { BIO_get_fd(((SSL*)fd)->gnutls_state, &desc); }" TO g_FUNCTIONS
		ELSE
			WRITELN "if(__b2c__option_tls) { desc = SSL_get_fd((SSL*)fd); }" TO g_FUNCTIONS
		ENDIF
	ENDIF
	WRITELN "if(!__b2c__option_tls) { desc = fd; } }" TO g_FUNCTIONS
	WRITELN "FD_SET(desc, &rfds); retval = select(desc + 1, &rfds, NULL, NULL, &tv); if(retval == -1 && __b2c__trap) { ERROR = 16; RUNTIMEFERR(\"WAIT\", ERROR, k, l); }" TO g_FUNCTIONS
	WRITELN "if(fd == STDIN_FILENO){ if(retval) if(read(fd, &retval, 1)==0) retval=0; tcsetattr(STDIN_FILENO, TCSANOW, &oldt);} return(retval); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "extract") OR nolex THEN
	WRITELN "char *__b2c__extract(int l, char *k, char *src, char *needle, int flag) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; int reti, len, pos = 0; char *tmp; regex_t regex; char __b2c__buf[100]; regmatch_t where[1];" TO g_FUNCTIONS
	WRITELN "if (src == NULL || needle == NULL) { return (src); } if (__b2c__len(src) == 0 || __b2c__len(needle) == 0) { return(src); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len(src) + 1);" TO g_FUNCTIONS
	WRITELN "if (flag > 0) { if (__b2c__option_compare == 0) reti = regcomp (&regex, needle, REG_EXTENDED); else reti = regcomp (&regex, needle, REG_EXTENDED | REG_ICASE);" TO g_FUNCTIONS
	WRITELN "if (__b2c__trap && reti) { ERROR = 27; regerror (reti, &regex, __b2c__buf, sizeof (__b2c__buf)); fprintf (stderr, \"%s\\n\", __b2c__buf); RUNTIMEFERR(\"EXTRACT$\", ERROR, k, l); }" TO g_FUNCTIONS
	WRITELN "while ((reti = regexec (&regex, src, 1, where, 0)) == 0) { memcpy(buf[idx] + pos, src, (size_t) where[0].rm_so); pos += where[0].rm_so; src += (long) where[0].rm_eo;}" TO g_FUNCTIONS
	WRITELN "regfree (&regex); len = strlen(src); memcpy(buf[idx] + pos, src, len); pos += len; } else { while ((tmp = strstr (src, needle)) != NULL)" TO g_FUNCTIONS
	WRITELN "{ memcpy(buf[idx] + pos, src, (size_t) (tmp - src) ); pos += tmp - src; src = tmp + __b2c__len(needle); }" TO g_FUNCTIONS
	WRITELN "len = strlen(src); memcpy(buf[idx] + pos, src, len ); pos += len; }__b2c__SETLEN(buf[idx], pos); buf[idx][pos] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "regex") OR nolex THEN
	WRITELN "long __b2c__regex(int l, char *k, char* x, char* y){regex_t reg; int reti; char buf[100]; regmatch_t where[1]; if(x == NULL || y == NULL) return(0); if(__b2c__option_compare == 0) { reti = regcomp(&reg, y, REG_EXTENDED); }" TO g_FUNCTIONS
	WRITELN "else { reti = regcomp(&reg, y, REG_EXTENDED|REG_ICASE); } if(__b2c__trap && reti){ERROR=27; regerror(reti, &reg, buf, sizeof(buf)); fprintf(stderr, \"%s\\n\", buf); RUNTIMEFERR(\"REGEX\", ERROR, k, l);}" TO g_FUNCTIONS
	WRITELN "reti = regexec(&reg, x, 1, where, 0); regfree(&reg); if(!reti) {REGLEN = where[0].rm_eo - where[0].rm_so; return (where[0].rm_so+1);} else { REGLEN = 0; return (0);} }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "replace") OR nolex THEN
	WRITELN "char *__b2c__replace(int l, char *k, char *haystack, char *needle, char *replace, int flag) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; char *tmp; long replen, hstlen, ndllen, length = 0; regex_t regex; int i, reti; char buffer[100]; regmatch_t where[1];" TO g_FUNCTIONS
	WRITELN "if(haystack == NULL || needle == NULL) { return (haystack); } if(replace==NULL) { replace = EmptyString; } ndllen = __b2c__len(needle); hstlen = __b2c__len(haystack);" TO g_FUNCTIONS
	WRITELN "if(hstlen == 0 || ndllen == 0) { return(haystack); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } if (flag == 2) { buf[idx] = (char*)__b2c_str_realloc(buf[idx], hstlen+1); strncpy(buf[idx], haystack, hstlen); for (i = 0; i < hstlen; i++){ if ((tmp = strchr (needle, buf[idx][i])) != NULL)" TO g_FUNCTIONS
	WRITELN "{buf[idx][i] = replace[tmp - needle]; } } __b2c__SETLEN(buf[idx], i); buf[idx][i] = '\\0'; return(char*)(buf[idx]); } buf[idx] = (char*)__b2c_str_realloc(buf[idx], sizeof (char)); buf[idx][0] = '\\0';" TO g_FUNCTIONS
	WRITELN "replen = __b2c__len(replace); if (flag == 1) { if (__b2c__option_compare == 0) reti = regcomp (&regex, needle, REG_EXTENDED); else reti = regcomp (&regex, needle, REG_EXTENDED | REG_ICASE); if (__b2c__trap && reti) { ERROR = 27;" TO g_FUNCTIONS
	WRITELN "regerror (reti, &regex, buffer, sizeof(buffer)); fprintf(stderr, \"%s\\n\", buffer); RUNTIMEFERR(\"REPLACE$\", ERROR, k, l); } while ((reti = regexec (&regex, haystack, 1, where, 0)) == 0) { buf[idx] = (char*)__b2c_str_realloc(buf[idx], length + where[0].rm_so + replen + 1);" TO g_FUNCTIONS
	WRITELN "memcpy(buf[idx] + length, haystack, (size_t) where[0].rm_so); length += where[0].rm_so; memcpy(buf[idx] + length, replace, replen); length += replen; haystack += (long) where[0].rm_eo; } regfree (&regex); }" TO g_FUNCTIONS
	WRITELN "else { while ((tmp = strstr (haystack, needle)) != NULL) { buf[idx] = (char*)__b2c_str_realloc(buf[idx], length + tmp - haystack + replen + 1); memcpy(buf[idx] + length, haystack, (size_t) (tmp - haystack)); length += tmp - haystack;" TO g_FUNCTIONS
	WRITELN "memcpy(buf[idx] + length, replace, replen); length += replen; haystack = tmp + ndllen; }} hstlen = strlen (haystack); buf[idx] = (char*)__b2c_str_realloc(buf[idx], length + hstlen + 1); memcpy(buf[idx] + length, haystack, hstlen);" TO g_FUNCTIONS
	WRITELN "length += hstlen; __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "walk") OR nolex THEN
	WRITELN "#ifndef PATH_MAX" TO g_FUNCTIONS
	WRITELN "#define PATH_MAX 4096" TO g_FUNCTIONS
	WRITELN "#endif" TO g_FUNCTIONS
	WRITELN "static int __b2c__walk_filter_file(regex_t reg, char *file, int type, struct stat bf) { regmatch_t where[1]; if (regexec(&reg, file, 1, where, 0) == 0) { if (((type & 1) && S_ISREG(bf.st_mode)) || ((type & 2) && S_ISDIR(bf.st_mode)) || ((type & 4) && S_ISCHR(bf.st_mode)) || ((type & 8) && S_ISBLK(bf.st_mode)) ||" TO g_FUNCTIONS
	WRITELN " ((type & 16) && S_ISFIFO(bf.st_mode)) || ((type & 32) && S_ISLNK(bf.st_mode)) || ((type & 64) && S_ISSOCK(bf.st_mode))) { return(1); } } return(0); }" TO g_FUNCTIONS
	WRITELN "static int __b2c__walk_each_file_recurse(regex_t reg, char **buf, char *dir, int type, char *delim) { FTS *fts; FTSENT *ent; struct stat bf; char *item[2]; int dlen, flen, total = 0, result = 0; item[0] = dir; item[1] = NULL; fts = fts_open(item, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL); if(fts == NULL)" TO g_FUNCTIONS
	WRITELN "{ return(-1); } dlen = __b2c__len(delim); while(1) { ent = fts_read(fts); if(ent == NULL) { break; } if (lstat(ent->fts_path, &bf) < 0 && __b2c__trap) { result = -1; break; } if(__b2c__walk_filter_file(reg, ent->fts_path, type, bf))" TO g_FUNCTIONS
	WRITELN "{ if(ent->fts_info != FTS_D) { flen = __b2c__len(ent->fts_path); *buf = (char*)__b2c_str_realloc(*buf, total+flen+dlen+1); memcpy(*buf+total, ent->fts_path, flen); memcpy(*buf+total+flen, delim, dlen);" TO g_FUNCTIONS
	WRITELN "total += flen + dlen; } } } if(total == 0) { dlen = 0; } __b2c__SETLEN(*buf, total-dlen); (*buf)[total - dlen] = '\\0'; fts_close(fts); return (result); }" TO g_FUNCTIONS
	WRITELN "static int __b2c__walk_each_file_dir (regex_t reg, char **buf, const char *dir, int type, char *delim) { DIR *here; struct dirent *item; struct stat bf; int dlen, flen, plen, total = 0, result = 0; char path[PATH_MAX] = { 0 }; here = opendir (dir); if (here == NULL) { return (-1); } dlen = __b2c__len(delim); plen = strlen(dir);" TO g_FUNCTIONS
	WRITELN "if (plen >= PATH_MAX) { return (-1); } strncpy (path, dir, PATH_MAX - 1); plen++; if (plen >= PATH_MAX) { return (-1); } strncat (path, \"/\", PATH_MAX - plen - 1); while (1) { item = readdir (here); if (item == NULL) { break; } if (!strcmp (item->d_name, \".\") || !strcmp (item->d_name, \"..\")) { continue; } memset (path + plen, 0, 1);" TO g_FUNCTIONS
	WRITELN "flen = strlen(item->d_name); if (plen + flen >= PATH_MAX) { return (-1); } strncat (path, item->d_name, PATH_MAX - plen - 1); flen += plen; if (lstat (path, &bf) < 0 && __b2c__trap) { result = -1; break; } if (__b2c__walk_filter_file (reg, path, type, bf)) { *buf = (char*)__b2c_str_realloc(*buf, total + flen + dlen + 1);" TO g_FUNCTIONS
	WRITELN "memcpy(*buf+total, path, flen); memcpy(*buf+total+flen, delim, dlen); total += flen + dlen; } } if(total == 0) { dlen = 0; } __b2c__SETLEN(*buf, total - dlen); (*buf)[total - dlen] = '\\0'; closedir (here); return (result); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__walk (int l, char *k, char *dir, int type, char *exp, int recurse, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; regex_t reg; char buffer[100]; int reti; if (dir == NULL || exp == NULL) { return (EmptyString); } if (delim == NULL) { delim = __b2c__option_delim; } if ((type < 1 || type > 127) && __b2c__trap)" TO g_FUNCTIONS
	WRITELN "{ ERROR = 5; RUNTIMEFERR(\"WALK$\", ERROR, k, l); } if (__b2c__option_compare == 0) { reti = regcomp(&reg, exp, REG_EXTENDED); } else { reti = regcomp(&reg, exp, REG_EXTENDED | REG_ICASE); } if (__b2c__trap && reti) { ERROR = 27; regerror (reti, &reg, buffer, sizeof(buffer)); fprintf(stderr, \"%s\\n\", buffer);" TO g_FUNCTIONS
	WRITELN "RUNTIMEFERR(\"WALK$\", ERROR, k, l); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], PATH_MAX*sizeof(char)); if (recurse) { if (__b2c__walk_each_file_recurse(reg, &buf[idx], dir, type, delim) == -1) { ERROR = 24; RUNTIMEFERR(\"WALK$\", ERROR, k, l); } } else { if (__b2c__walk_each_file_dir(reg, &buf[idx], dir, type, delim) == -1)" TO g_FUNCTIONS
	WRITELN "{ ERROR = 24; RUNTIMEFERR(\"WALK$\", ERROR, k, l); } } regfree(&reg); return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "eval") OR g_OPTION_EVAL THEN
	WRITELN "#include <matheval.h>" TO g_FUNCTIONS
	WRITELN "double __b2c__eval(int l, char *k, char **vars, double *vals, int nr, char *expr) { void *f; double result; if (expr == NULL) return (0); f = evaluator_create(expr);" TO g_FUNCTIONS
	WRITELN "if(f) { result = evaluator_evaluate(f, nr, vars, vals); } else if (__b2c__trap) { ERROR = 39; RUNTIMEFERR(\"EVAL\", ERROR, k, l); } evaluator_destroy(f); return(result); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "getfile") OR nolex THEN
	WRITELN "void __b2c__getfile(char **result, DIR *from) { struct dirent *dir; dir = readdir(from); if(dir != NULL) { *result = __b2c__strdup(dir->d_name); } else { *result = (char*)calloc(1, sizeof(char)); } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "copy") OR nolex THEN
	WRITELN "int __b2c__copy(const char *from, const char *to) { char buffer[", g_BUFFER_SIZE, "]; FILE *in, *out; size_t size; in = fopen(from, \"r\"); out = fopen(to, \"w\");" TO g_FUNCTIONS
	WRITELN "while((size = fread(buffer, sizeof(char), ", g_BUFFER_SIZE, ", in)) > 0) { if(fwrite(buffer, sizeof(char), size, out) != size) { return(1); } } fclose(in); fclose(out); return(0); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "input") OR nolex THEN
	WRITELN "void __b2c__input(char **result, char *sep) { size_t size; ssize_t total; size = ", g_BUFFER_SIZE, "; *result = (char*)calloc(", g_BUFFER_SIZE, ", sizeof(char));" TO g_FUNCTIONS
	WRITELN "total = getdelim(&(*result), &size, ASC(sep), stdin); if(total > 0 && (*result)[total-1] == ASC(sep)) { (*result)[total-1] = '\\0'; } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "readln") OR nolex THEN
	WRITELN "void __b2c__readln(char **result, FILE *from) { size_t size; ssize_t total; size = ", g_BUFFER_SIZE, "; *result = (char*)calloc(", g_BUFFER_SIZE, ", sizeof(char));" TO g_FUNCTIONS
	WRITELN "total = getline(&(*result), &size, from); if(total > 0 && (*result)[total-1] == '\\n') { (*result)[total-1] = '\\0'; } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "return") OR nolex THEN
	WRITELN "char *__b2c__return(char *data) { static char* rbuffer[", g_MAX_RBUFFERS, "] = { NULL }; static size_t rbuffer_len[", g_MAX_RBUFFERS, "] = { 0 }; static int rbuffer_ptr = 0;" TO g_FUNCTIONS
	WRITELN "size_t size; rbuffer_ptr++; if(rbuffer_ptr >= ", g_MAX_RBUFFERS, "){ rbuffer_ptr=0; } if(data != NULL){ size = __b2c__len(data); if(rbuffer_len[rbuffer_ptr] < size+1)" TO g_FUNCTIONS
	WRITELN "{ rbuffer_len[rbuffer_ptr] = (size_t)(size*4+1); rbuffer[rbuffer_ptr] = (char*)realloc(rbuffer[rbuffer_ptr], rbuffer_len[rbuffer_ptr]*sizeof(char)); } strncpy(rbuffer[rbuffer_ptr], data, size+1); }" TO g_FUNCTIONS
	WRITELN "else { if(rbuffer[rbuffer_ptr]) { rbuffer[rbuffer_ptr] = EmptyString; } else { rbuffer[rbuffer_ptr] = (char*)calloc(1, sizeof(char)); } } return(rbuffer[rbuffer_ptr]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "join") OR nolex THEN
	WRITELN "void __b2c__join (char **result, char **array, int base, int size, char *by) { long dlen, i, slen, total; dlen = __b2c__len (by); total = __b2c__len (array[0 + base]);" TO g_FUNCTIONS
	WRITELN "*result = (char*)calloc(total, sizeof(char)+1); memmove(*result, array[0 + base], total); for (i = 1; i < size; i++) { if (array[i + base] != NULL) { slen = __b2c__len (array[i + base]);" TO g_FUNCTIONS
	WRITELN "*result = (char *) realloc (*result, (total + dlen + slen + 1) * sizeof (char)); memmove (*result + total, by, dlen); total += dlen; memmove (*result + total, array[i + base], slen);" TO g_FUNCTIONS
	WRITELN "total += slen; } } (*result)[total] = '\\0'; }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "network") OR nolex THEN
	IF TALLY(g_LIB_TLS$, "gnutls") THEN
		WRITELN "#define SSL_set_tlsext_host_name(connection, name) gnutls_server_name_set(((SSL*)connection)->gnutls_state, GNUTLS_NAME_DNS, name, LEN(name))" TO g_FUNCTIONS
		WRITELN "#undef VERIFY" TO g_FUNCTIONS
		WRITELN "long VERIFY(uintptr_t ssl, char* pem) { int result = 0; gnutls_certificate_credentials_t cred = 0; if((SSL*)ssl == NULL) { return(-1); }" TO g_FUNCTIONS
		WRITELN "gnutls_certificate_allocate_credentials(&cred); gnutls_certificate_set_x509_trust_file(cred, pem, GNUTLS_X509_FMT_PEM);" TO g_FUNCTIONS
		WRITELN "if(gnutls_credentials_set(((SSL*)ssl)->gnutls_state, GNUTLS_CRD_CERTIFICATE, cred) != 0) { return(-1); } if(gnutls_certificate_verify_peers2(((SSL*)ssl)->gnutls_state, &result) !=0) { return(-1); }" TO g_FUNCTIONS
		WRITELN "gnutls_certificate_free_credentials(cred); return(result); }" TO g_FUNCTIONS
	ENDIF
	WRITELN "int __b2c__network_init(uintptr_t *handle, char *site, char *org, int sock_type, int sock_opt, char *nw_type, int multicast_ttl, int sctp_streams, int capeer, char *cacerts) { struct sockaddr_in *addr, *from; struct hostent *he;" TO g_FUNCTIONS
	WRITELN "long amount = 0; long length = 0; char data_client[", g_BUFFER_SIZE, "]; char *host, *local, *port, *from_client; struct timeval tval; int sock, i, yes = 1; long start; char ttl = 1; __b2c__delim_engine (2, &amount, site, \",\", 0);" TO g_FUNCTIONS
	WRITELN "addr = (struct sockaddr_in*)calloc(amount, sizeof(*addr)); for(i = 0; i < amount; i++) { start = __b2c__delim_engine (1, &length, site, \",\", i+1); if(length >= ", g_BUFFER_SIZE, ") { return(5); } memset(data_client, 0, ", g_BUFFER_SIZE, ");" TO g_FUNCTIONS
	WRITELN "strncpy(data_client, site+start, length); if(strstr(data_client, \":\") == NULL) { return(10); } host = strtok(data_client, \":\"); port = strtok(NULL, \":\"); he = gethostbyname(host); if(he == NULL || he->h_addr == NULL) { return(11); }" TO g_FUNCTIONS
	WRITELN "addr[i].sin_family = AF_INET; addr[i].sin_port = htons((long)atol(port)); addr[i].sin_addr = *((struct in_addr *) he->h_addr); }" TO g_FUNCTIONS
	IF g_NETWORKTYPE$ = "SCTP" THEN
		WRITELN "sock = socket(AF_INET, sock_type, IPPROTO_SCTP);" TO g_FUNCTIONS
	ELSE
		WRITELN "sock = socket(AF_INET, sock_type, 0);" TO g_FUNCTIONS
	ENDIF
	WRITELN "if(sock == -1) { return(12); } tval.tv_sec = sock_opt; tval.tv_usec = 0; setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tval, sizeof (struct timeval));" TO g_FUNCTIONS
	WRITELN "setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)); if(org) { __b2c__delim_engine (2, &amount, org, \",\", 0); from = (struct sockaddr_in*)calloc(amount, sizeof(*from));" TO g_FUNCTIONS
	WRITELN "for(i = 0; i < amount; i++) { start = __b2c__delim_engine (1, &length, site, \",\", i+1); from_client = __b2c__strndup(org+start, length); if(strstr(from_client, \":\"))" TO g_FUNCTIONS
	WRITELN "{ local = strtok(from_client, \":\"); port = strtok(NULL, \":\"); } else { local = from_client; port = NULL; } he = gethostbyname(local); if(he == NULL || he->h_addr == NULL) { return(11); }" TO g_FUNCTIONS
	WRITELN "from[i].sin_family = AF_INET; if(port) { from[i].sin_port = htons((long)atol(port)); } from[i].sin_addr = *((struct in_addr *)he->h_addr); free(from_client); }" TO g_FUNCTIONS
	IF g_NETWORKTYPE$ = "SCTP" THEN
		WRITELN "if(sctp_bindx(sock, (struct sockaddr *)from, 1, SCTP_BINDX_ADD_ADDR) < 0) { return(17); } free(from); }" TO g_FUNCTIONS
		WRITELN "struct sctp_initmsg initmsg; memset (&initmsg, 0, sizeof (initmsg)); initmsg.sinit_max_attempts = 3; initmsg.sinit_num_ostreams = sctp_streams; initmsg.sinit_max_instreams = sctp_streams;" TO g_FUNCTIONS
		WRITELN "setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof (initmsg));", NL$, "#ifdef SCTP_SOCKOPT_CONNECTX_OLD", NL$, "if(sctp_connectx(sock, (struct sockaddr *) addr, 1, NULL) < 0) { return(13); }" TO g_FUNCTIONS
		WRITELN "#else", NL$, "if(sctp_connectx(sock, (struct sockaddr *) addr, 1) < 0) { return(13); }", NL$, "#endif" TO g_FUNCTIONS
	ELSE
		WRITELN "if(bind(sock, (struct sockaddr *)from, sizeof(struct sockaddr)) < 0) { return(17); } free(from); }" TO g_FUNCTIONS
		WRITELN "if (!strcmp(nw_type, \"BROADCAST\")) { setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(int)); } if(!strcmp(nw_type, \"MULTICAST\")) { setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &yes, sizeof(int));" TO g_FUNCTIONS
		WRITELN "ttl = multicast_ttl; setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(unsigned char)); }" TO g_FUNCTIONS
		WRITELN "if(connect(sock, (struct sockaddr*)addr, sizeof(struct sockaddr)) < 0) { return(13); }" TO g_FUNCTIONS
	ENDIF
	WRITELN "*handle = sock;" TO g_FUNCTIONS
	IF g_OPTION_TLS THEN
		WRITELN "if(__b2c__option_tls) { int ret; static SSL_CTX *ssl_context = NULL; SSL *ssl_sock; SSL_library_init(); if(ssl_context == NULL) { ssl_context = SSL_CTX_new(TLS_client_method()); } SSL_CTX_set_verify(ssl_context, capeer, NULL);" TO g_FUNCTIONS
		IF NOT(TALLY(g_LIB_TLS$, "gnutls")) THEN WRITELN "SSL_CTX_load_verify_locations(ssl_context, cacerts, NULL);" TO g_FUNCTIONS
		WRITELN "ssl_sock = SSL_new(ssl_context); SSL_set_tlsext_host_name(ssl_sock, host); if(SSL_set_fd(ssl_sock, *handle) == 0) { return(40); }" TO g_FUNCTIONS
		WRITELN "if((ret = SSL_connect(ssl_sock)) <= 0) { fprintf(stderr, \"SSL CONNECT error: %s\\n\", ERR_error_string(SSL_get_error(ssl_sock, ret), NULL)); return(40); }" TO g_FUNCTIONS
		WRITELN "*handle = (uintptr_t)ssl_sock; }" TO g_FUNCTIONS
	ENDIF
	WRITELN "free(addr); return(0); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "server") OR nolex THEN
	WRITELN "int __b2c__server_init(uintptr_t *handle, char *site, int sock_type, int sock_opt, int sctp_streams) { struct sockaddr_in *addr; struct hostent *he; long amount = 0; long length = 0; char *host, *port;" TO g_FUNCTIONS
	WRITELN "char data_client[", g_BUFFER_SIZE, "]; struct timeval tval; int fd, i, yes = 1; long start; __b2c__delim_engine (2, &amount, site, \",\", 0); addr = (struct sockaddr_in*)calloc(amount, sizeof(*addr)); for(i = 0; i < amount; i++)" TO g_FUNCTIONS
	WRITELN "{ start = __b2c__delim_engine(1, &length, site, \",\", i + 1); if (length >= ", g_BUFFER_SIZE, ") { return (5); } memset (data_client, 0, ", g_BUFFER_SIZE, "); strncpy(data_client, site + start, length);" TO g_FUNCTIONS
	WRITELN "if(strstr(data_client, \":\") == NULL) { return(10); } host = strtok(data_client, \":\"); port = strtok(NULL, \":\"); if(strstr(site, \"INADDR_ANY:\") || strstr(site, \"*:\")) { addr[i].sin_addr.s_addr = htonl(INADDR_ANY); }" TO g_FUNCTIONS
	WRITELN "else { he = gethostbyname(host); if(he == NULL || he->h_addr == NULL) { return(11); } addr[i].sin_addr = *((struct in_addr*)he->h_addr); }" TO g_FUNCTIONS
	WRITELN "addr[i].sin_family = AF_INET; addr[i].sin_port = htons((long)atol(port)); }" TO g_FUNCTIONS
	IF g_NETWORKTYPE$ = "SCTP" THEN
		WRITELN "fd = socket(AF_INET, sock_type, IPPROTO_SCTP);" TO g_FUNCTIONS
		WRITELN "struct sctp_initmsg initmsg; memset(&initmsg, 0, sizeof(initmsg)); initmsg.sinit_max_attempts = 3;" TO g_FUNCTIONS
		WRITELN "initmsg.sinit_num_ostreams = sctp_streams; initmsg.sinit_max_instreams = sctp_streams;" TO g_FUNCTIONS
		WRITELN "setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));" TO g_FUNCTIONS
	ELSE
		WRITELN "fd = socket(AF_INET, sock_type, 0);" TO g_FUNCTIONS
	ENDIF
	WRITELN "if(fd == -1) { return(12); } tval.tv_sec = sock_opt; tval.tv_usec = 0; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tval, sizeof(struct timeval));" TO g_FUNCTIONS
	WRITELN "setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));" TO g_FUNCTIONS
	IF g_NETWORKTYPE$ = "SCTP" THEN
		WRITELN "if(sctp_bindx(fd, (struct sockaddr *)addr, 1, SCTP_BINDX_ADD_ADDR) < 0) { return(17); }" TO g_FUNCTIONS
	ELSE
		WRITELN "if(bind(fd, (struct sockaddr *)addr, sizeof(struct sockaddr)) < 0) { return(17); }" TO g_FUNCTIONS
	ENDIF
	IF g_NETWORKTYPE$ = "MULTICAST" THEN
		WRITELN "struct ip_mreq imreq; imreq.imr_multiaddr.s_addr = inet_addr(host); imreq.imr_interface.s_addr = INADDR_ANY;" TO g_FUNCTIONS
		WRITELN "setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(imreq));" TO g_FUNCTIONS
	ENDIF
	IF g_NETWORKTYPE$ <> "UDP" AND g_NETWORKTYPE$ <> "BROADCAST" AND g_NETWORKTYPE$ <> "MULTICAST" THEN
		WRITELN "if(listen(fd, ", g_MAX_BACKLOG, ") < 0) { return(18); }" TO g_FUNCTIONS
	ENDIF
	WRITELN "*handle = fd; free(addr); return(0); }" TO g_FUNCTIONS
	WRITELN "uintptr_t __b2c__accept(int l, char *k, char *priv, char *cert, uintptr_t fd) { uintptr_t handle; int desc, result; desc = accept(fd, NULL, 0); if(desc < 0){ ERROR = 19; RUNTIMEFERR(\"ACCEPT\", ERROR, k, l); }" TO g_FUNCTIONS
	IF g_OPTION_TLS THEN
		WRITELN "if(__b2c__option_tls) { static SSL_CTX *ssl_context = NULL; SSL *ssl_sock = NULL; if(ssl_context == NULL) { SSL_library_init(); ssl_context = SSL_CTX_new(TLS_server_method());" TO g_FUNCTIONS
		WRITELN "if(SSL_CTX_use_PrivateKey_file(ssl_context, priv, SSL_FILETYPE_PEM) <= 0) { return(41); } if(SSL_CTX_use_certificate_file(ssl_context, cert, SSL_FILETYPE_PEM) <= 0) { return(41); } }" TO g_FUNCTIONS
		WRITELN "ssl_sock = SSL_new(ssl_context); SSL_set_fd(ssl_sock, desc); if((result = SSL_accept(ssl_sock)) <= 0){ fprintf(stderr, \"SSL ACCEPT error: %s\\n\", ERR_error_string(SSL_get_error(ssl_sock, result), NULL));" TO g_FUNCTIONS
		WRITELN "SSL_shutdown((SSL*)ssl_sock); SSL_free((SSL*)ssl_sock); return(-1); } handle = (uintptr_t)ssl_sock; }" TO g_FUNCTIONS
	ELSE
		WRITELN "if(!__b2c__option_tls) { handle = (uintptr_t)desc; }" TO g_FUNCTIONS
	ENDIF
	WRITELN "return(handle); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "save") OR nolex THEN
	WRITELN "int __b2c__save(int mode, int size, char *file, ...) { FILE *outfile; va_list args; char *item; switch(mode){ case 0: case 1: outfile = fopen((const char *) file, \"w\"); break;" TO g_FUNCTIONS
	WRITELN "case 2: case 3: outfile = fopen((const char *) file, \"a\"); break; } if (outfile == NULL) { return(2); } switch(mode) { case 0: case 2: va_start(args, file); while((item = va_arg(args, char*)) != NULL)" TO g_FUNCTIONS
	WRITELN "{ fprintf(outfile, \"%s\", item); } va_end(args); break; case 1: case 3: va_start(args, file); if(fwrite(va_arg(args, void*), 1, size, outfile) != size){ return(2); } va_end(args); break; } fclose (outfile); return(0); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "setserial") OR nolex THEN
	WRITELN "int __b2c_setserial(int device, int mode, int param, int value, int donot) { struct termios tty; memset(&tty, 0, sizeof(tty)); if(tcgetattr(device, &tty) != 0) { return(33); } switch(mode)" TO g_FUNCTIONS
	WRITELN "{ case 0: if(donot) { tty.c_iflag &= value; } else { tty.c_iflag |= value; } break; case 1: if(donot) { tty.c_oflag &= value; } else { tty.c_oflag |= value; } break; case 2: if(donot) { tty.c_cflag &= value; }" TO g_FUNCTIONS
	WRITELN "else { tty.c_cflag |= value; } break; case 3: if(donot) { tty.c_lflag &= value; } else { tty.c_lflag |= value; } break; case 4: tty.c_cc[param] = value; break; case 5: cfsetospeed(&tty, value); cfsetispeed(&tty, value);" TO g_FUNCTIONS
	WRITELN "break; } if(tcsetattr(device, TCSANOW, &tty) != 0) { return(33); } return(0); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "getline") OR nolex THEN
	WRITELN "char *__b2c__getline(char **handle) { char *pos, *result; if(*handle == NULL || (*handle)[0] == '\\0') { return(__b2c__strdup(EmptyString)); } else { pos = strchr(*handle, '\\n'); if(pos)" TO g_FUNCTIONS
	WRITELN "{ result = __b2c__strndup(*handle, (size_t)(pos - *handle)); } else { result = __b2c__strdup(*handle); } *handle += __b2c__len(result); if((*handle)[0] == '\\n') { (*handle)++; } } return(result); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "split") OR nolex THEN
	WRITELN "void __b2c__split_by(char ***array, int base, long *amount, char *string, char *by) { long length, i, start; char *ptr; __b2c__free_str_array_members(&(*array), base, *amount); free(*array);" TO g_FUNCTIONS
	WRITELN "*array = NULL; start = __b2c__delim_engine(2, amount, string, by, 0); *array = (char**)realloc(*array, (*amount+base) * sizeof(char*)); ptr = string; for (i = 0; i < *amount; i++)" TO g_FUNCTIONS
	WRITELN "{ start = __b2c__delim_engine(1, &length, ptr, by, 1); (*array)[i + base] =__b2c__strndup(ptr + start, (size_t)length); ptr += start + length + __b2c__len(by); } }" TO g_FUNCTIONS
	WRITELN "void __b2c__split_with(char ***array, int base, long *amount, char *string, int counter) { long length, i; __b2c__free_str_array_members (&(*array), base, *amount); free(*array); *array = NULL;" TO g_FUNCTIONS
	WRITELN "length = __b2c__len(string); if (counter > length) { counter = length; } *amount = (length / counter) + (length % counter != 0 ? 1 : 0); *array = (char**)realloc(*array, (*amount+base)*sizeof(char*));" TO g_FUNCTIONS
	WRITELN "if (counter > 0) { for (i = 0; i < *amount; i++) { (*array)[i + base] = __b2c__strndup(string + i*counter, (size_t)counter); } } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "for") OR nolex THEN
	WRITELN "long __b2c__for_amount(char *string, char *step) { long amount = 0; __b2c__delim_engine(2, &amount, string, step, 0); return(amount); }" TO g_FUNCTIONS
	WRITELN "void __b2c__for_item(char **string, char *step, char **result) { long length = 0; long start; start = __b2c__delim_engine (1, &length, *string, step, 1);" TO g_FUNCTIONS
	WRITELN "*result = (char*)__b2c_str_realloc(*result, length + 1); memmove(*result, *string + start, length); __b2c__SETLEN (*result, length); (*result)[length] = '\\0'; *string += (start + length + __b2c__len(step)); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "makedir") OR nolex THEN
	WRITELN "int __b2c__makedir(char *newdir) { long start, amount = 0, length = 0; int item, collapse; char *dir; if (newdir != NULL && *newdir != 0) { collapse = __b2c__collapse; __b2c__collapse = 0; dir = (char*)calloc(__b2c__len(newdir)+1, sizeof(char));" TO g_FUNCTIONS
	WRITELN "start = __b2c__delim_engine(2, &amount, newdir, \"/\", 0); for(item = 1; item <= amount; item++) { start = __b2c__delim_engine(1, &length, newdir, \"/\", item); if(length) { strncat(dir, newdir+start, length);" TO g_FUNCTIONS
	WRITELN "if(mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0 && errno != EEXIST && errno != 0) { return(21); } } if(item < amount) { strcat(dir, \"/\"); } } free(dir); __b2c__collapse = collapse; } return(0); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "alarm") OR nolex THEN
	WRITELN "void __b2c__alarm(void *func, long time) { void(*target)(int); struct itimerval alarm; struct sigaction psa; memset(&psa, 0, sizeof(psa)); psa.sa_flags = SA_RESETHAND|SA_RESTART;" TO g_FUNCTIONS
	WRITELN "*((void**)&target) = func; psa.sa_handler = target; sigaction(SIGALRM, &psa, NULL); alarm.it_value.tv_sec = (long)(time)/1000; alarm.it_value.tv_usec = ((time)%1000)*1000;" TO g_FUNCTIONS
	WRITELN "alarm.it_interval.tv_sec = 0; alarm.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &alarm, NULL); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "signal") OR nolex THEN
	WRITELN "void __b2c__signal(void *func, int action) { void(*target)(int); struct sigaction psa; memset(&psa, 0, sizeof(psa)); *((void**)&target) = func; psa.sa_handler = target; sigaction(action, &psa, NULL); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "cipher") OR g_OPTION_TLS THEN
	WRITELN "char *__b2c__ca(int l, char *k, uintptr_t desc) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long len; char buffer[4096] = { 0 }; X509 *cert; X509_NAME *name; if((SSL*)desc == NULL) { ERROR = 40; RUNTIMEFERR(\"CA$\", ERROR, k, l); } cert = (X509*)SSL_get_peer_certificate((SSL*)desc); if(cert==NULL) { ERROR = 41; RUNTIMEFERR(\"CA$\", ERROR, k, l); }" TO g_FUNCTIONS
	WRITELN "name = X509_get_issuer_name(cert); X509_NAME_oneline(name, buffer, 4095); len = strlen(buffer); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], len + 1); memmove(buf[idx], buffer, len);__b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0';" TO g_FUNCTIONS
	IF TALLY(g_LIB_TLS$, "gnutls") THEN WRITELN "free(name);" TO g_FUNCTIONS
	WRITELN "X509_free(cert); return(char*)(buf[idx]); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__cn(int l, char *k, uintptr_t desc) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long len; char buffer[4096] = { 0 }; X509 *cert; X509_NAME *name; if((SSL*)desc == NULL) { ERROR = 40; RUNTIMEFERR(\"CN$\", ERROR, k, l); } cert = (X509*)SSL_get_peer_certificate((SSL*)desc); if(cert==NULL) { ERROR = 41; RUNTIMEFERR(\"CA$\", ERROR, k, l); }" TO g_FUNCTIONS
	WRITELN "name = X509_get_subject_name(cert); X509_NAME_oneline(name, buffer, 4095); len = strlen(buffer); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], len + 1); memmove(buf[idx], buffer, len);__b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0';" TO g_FUNCTIONS
	IF TALLY(g_LIB_TLS$, "gnutls") THEN WRITELN "free(name);" TO g_FUNCTIONS
	WRITELN "X509_free(cert); return(char*)(buf[idx]); }" TO g_FUNCTIONS
	WRITELN "char *__b2c__cipher(int l, char *k, uintptr_t desc) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long len; char buffer[4096] = { 0 }; if((SSL*)desc == NULL) { ERROR = 40; RUNTIMEFERR(\"CIPHER$\", ERROR, k, l); } SSL_CIPHER_description(SSL_get_current_cipher((SSL*)desc), buffer, 4095);" TO g_FUNCTIONS
	WRITELN "len = strlen(buffer); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], len + 1); memmove(buf[idx], buffer, len);__b2c__SETLEN(buf[idx], len); buf[idx][len] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "doescape") OR nolex THEN
	WRITELN "char *__b2c__escape(int l, char *k, char *string) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long length = 0; unsigned int current; if (string == NULL) { return (string); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], sizeof(char));" TO g_FUNCTIONS
	WRITELN "while(*string) { current = __b2c__utf8toasc(string); if(current > 0xffff) { buf[idx] = (char *) __b2c_str_realloc (buf[idx], length + 11); snprintf(buf[idx]+length, 11, \"\\\\U%08X\", current); length += 10; } else if(current > 0x7f)" TO g_FUNCTIONS
	WRITELN "{ buf[idx] = (char *) __b2c_str_realloc(buf[idx], length + 7); snprintf(buf[idx]+length, 7, \"\\\\u%04X\", current); length += 6; } else { buf[idx] = (char *) __b2c_str_realloc(buf[idx], length + 2);" TO g_FUNCTIONS
	WRITELN "switch(current) { case 7: snprintf(buf[idx]+length, 3, \"\\\\a\"); length+=2; break; case 8: snprintf(buf[idx]+length, 3, \"\\\\b\"); length+=2; break; case 27: snprintf(buf[idx]+length, 3, \"\\\\e\"); length+=2; break;" TO g_FUNCTIONS
	WRITELN "case 12: snprintf(buf[idx]+length, 3, \"\\\\f\"); length+=2; break; case 10: snprintf(buf[idx]+length, 3, \"\\\\n\"); length+=2; break; case 13: snprintf(buf[idx]+length, 3, \"\\\\r\"); length+=2; break;" TO g_FUNCTIONS
	WRITELN "case 9: snprintf(buf[idx]+length, 3, \"\\\\t\"); length+=2; break; case 11: snprintf(buf[idx]+length, 3, \"\\\\v\"); length+=2; break; case 92: snprintf(buf[idx]+length, 3, \"\\\\\\\\\"); length+=2; break;" TO g_FUNCTIONS
	WRITELN "case 39: snprintf(buf[idx]+length, 3, \"\\\\'\"); length+=2; break; case 34: snprintf(buf[idx]+length, 3, \"\\\\\\\"\"); length+=2; break; case 63: snprintf(buf[idx]+length, 3, \"\\\\?\"); length+=2; break;" TO g_FUNCTIONS
	WRITELN "default: snprintf(buf[idx]+length, 2, \"%c\", current); length+=1; } } string += __b2c__blen(l, k, \"ESCAPE$\", string, 1, 0); } __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "unescape") OR nolex THEN
	WRITELN "char *__b2c__unescape(int l, char *k, char *string) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long len, tlen, length = 0; char *pos, *status = NULL; char hex[9], buffer[9]; uint32_t byte; if (string == NULL) { return (string); } idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; }" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char*)__b2c_str_realloc(buf[idx], sizeof(char)); while((pos = strchr (string, 92)) != NULL) { switch (*(pos + 1)) { case 'u': case 'U': buf[idx] = (char *) __b2c_str_realloc (buf[idx], length + (pos - string)); memcpy(buf[idx] + length, string, (size_t) (pos - string));" TO g_FUNCTIONS
	WRITELN "length += (uintptr_t) (pos - string); string = pos + 2; if (*(pos + 1) == 'u') { tlen = 4; } else { tlen = 8; } if (strlen (string) < tlen) { ERROR = 5; RUNTIMEFERR(\"UNESCAPE$\", ERROR, k, l); } strncpy (hex, string, tlen); hex[tlen] = '\\0';" TO g_FUNCTIONS
	WRITELN "byte = strtol (hex, &status, 16); len = __b2c_utf8_conv (byte, buffer); buf[idx] = (char*)__b2c_str_realloc(buf[idx], length + len); memcpy(buf[idx] + length, buffer, len); string += tlen; length += len;" TO g_FUNCTIONS
	WRITELN "break; default: buf[idx] = (char*)__b2c_str_realloc(buf[idx], length + (pos - string) + 1); memcpy(buf[idx] + length, string, (size_t) (pos - string)); length += (uintptr_t) (pos - string);" TO g_FUNCTIONS
	WRITELN "switch (*(pos + 1)) { case 'a': byte = 7; string = pos + 2; break; case 'b': byte = 8; string = pos + 2; break; case 'e': byte = 27; string = pos + 2; break; case 'f': byte = 12; string = pos + 2; break; case 'n': byte = 10; string = pos + 2; break;" TO g_FUNCTIONS
	WRITELN "case 'r': byte = 13; string = pos + 2; break; case 't': byte = 9; string = pos + 2; break; case 'v': byte = 11; string = pos + 2; break; case 92: byte = 92; string = pos + 2; break; case 39: byte = 39; string = pos + 2; break;" TO g_FUNCTIONS
	WRITELN "case 34: byte = 34; string = pos + 2; break; case 63: byte = 63; string = pos + 2; break; default: byte = (uint8_t)(*(pos)); string = pos + 1; } buf[idx][length] = (uint8_t) byte; length += 1; } } len = strlen (string);" TO g_FUNCTIONS
	WRITELN "buf[idx] = (char *) __b2c_str_realloc(buf[idx], length + len + 1); memcpy(buf[idx] + length, string, len); length += len; __b2c__SETLEN(buf[idx], length); buf[idx][length] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "tree") OR nolex THEN
	WRITELN "void __b2c__treestr(void *node, char *str, void **tree, int(*func)(const void*, const void*)) { void *result; if(node) { result = tsearch(node, tree, func); if(*(uintptr_t**)result != (uintptr_t*)node) { free(str); free(node); } } }" TO g_FUNCTIONS
	WRITELN "void __b2c__treenr(void *node, void **tree, int(*func)(const void*, const void*)) { void *result; if(node) { result = tsearch(node, tree, func); if(*(uintptr_t**)result != (uintptr_t*)node) { free(node); } } }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "find") OR nolex THEN
	WRITELN "void *__b2c__find(int (*func)(const void*, const void*), void* tree, void* node) { void *result; result = tfind((void*)&node, &tree, func); if(result == NULL) { return(NULL); } return((void*)*(uintptr_t**)result); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "collect") OR nolex THEN
	WRITELN "static void __b2c__collect_do(const void *node, VISIT which, int depth) { switch (which) { case postorder: case leaf: __b2c__twalk_idx++; __b2c__twalk_array = (void**)realloc(__b2c__twalk_array, sizeof(void*)*__b2c__twalk_idx);" TO g_FUNCTIONS
	WRITELN "__b2c__twalk_array[__b2c__twalk_idx-1] = *(uintptr_t**)node; break; } }" TO g_FUNCTIONS
	WRITELN "int __b2c__collect(void *tree, void ***array, int base) { int i, count; if(__b2c__twalk_array) { free(__b2c__twalk_array); __b2c__twalk_array = NULL; } __b2c__twalk_idx = 0; twalk(tree, __b2c__collect_do); count = base;" TO g_FUNCTIONS
	WRITELN "*array = (void**)calloc(__b2c__twalk_idx, sizeof(void*)); for (i = 0; i < __b2c__twalk_idx; i++) { (*array)[count++] = *(uintptr_t**)__b2c__twalk_array[i]; } return (count-base); }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "parse") OR nolex THEN
	WRITELN "void __b2c__parse(char ***array, int base, long *amount1, char *string, char *with, char *delim) { long dlen, start1, start2, amount2, length1, length2, tmplen, sublen = 0; int x, i = 0, wildcard = 0, next = 0; char *pos = NULL;" TO g_FUNCTIONS
	WRITELN "__b2c__free_str_array_members (&(*array), base, *amount1); free (*array); *array = NULL; if (string == NULL && with == NULL) { *amount1 = 0; return; } if (delim == NULL) { delim = __b2c__option_delim; }" TO g_FUNCTIONS
	WRITELN "start1 = __b2c__delim_engine (2, amount1, string, delim, 0); if(*amount1 == 0) { return; } *array = (char **) realloc (*array, (*amount1 + base) * sizeof (char *)); dlen = __b2c__len (delim);" TO g_FUNCTIONS
	WRITELN "for (x = 0; x < *amount1; x++) { start1 = __b2c__delim_engine (1, &length1, string, delim, 1); start2 = __b2c__delim_engine (1, &length2, with, delim, 1); if(!strncmp (with, \"?\", 1))" TO g_FUNCTIONS
	WRITELN "{ (*array)[i + base] = __b2c__strndup (string, (size_t) length1); i++; string += (start1 + length1 + dlen); with += (start2 + length2 + dlen); } else { next = 0; if(!strncmp (with, \"*\", 1))" TO g_FUNCTIONS
	WRITELN "{ wildcard = 1; if(!pos) { pos = string; } __b2c__delim_engine (2, &amount2, with + 1, delim, 0); if(amount2) { next = 1 + dlen; } else { next = 1; } } else if(!strncmp(with, \"\\\\*\", 2) || !strncmp(with, \"\\\\?\", 2))" TO g_FUNCTIONS
	WRITELN "{ with++; length2--; } __b2c__delim_engine (1, &tmplen, with + next, delim, 1); if(length1 != tmplen || memcmp(string, with+next, tmplen)) { if (wildcard == 1) { if(sublen == 0) { sublen += length1; } else { sublen += length1 + dlen; } } else { __b2c__free_str_array_members (&(*array), base, i);" TO g_FUNCTIONS
	WRITELN "free (*array); *array = NULL; i = 0; break; } } else { if(wildcard) { (*array)[i + base] = __b2c__strndup(pos, (size_t)sublen); pos = NULL; sublen = 0; i++; } wildcard = 0; }" TO g_FUNCTIONS
	WRITELN "string += (start1 + length1 + dlen); if (wildcard == 0) { with += (start2 + length1 + dlen + next); } } } if (wildcard) { (*array)[i + base] = __b2c__strndup (pos, (size_t) sublen); i++; } *amount1 = i; }" TO g_FUNCTIONS
ENDIF

IF TALLY(total$, "collapsefunc") OR nolex THEN
	WRITELN "char *__b2c__collapse_func(char *string, char *delim) { static char *buf[__b2c_STRING_FUNC] = { NULL }; static int idx = 0; long start, dlen, option, x, total = 0; long amount = 0, length = 0; if (string == NULL) { return (string); } if (delim == NULL) { delim = __b2c__option_delim; }" TO g_FUNCTIONS
	WRITELN "option = __b2c__collapse; __b2c__collapse = 1; dlen = __b2c__len (delim); idx++; if(idx == __b2c_STRING_FUNC) { idx = 0; } buf[idx] = (char*)__b2c_str_realloc(buf[idx], __b2c__len (string) + 1); __b2c__delim_engine(2, &amount, string, delim, 0); for (x = 0; x < amount; x++)" TO g_FUNCTIONS
	WRITELN "{ start = __b2c__delim_engine (1, &length, string, delim, 1); memmove(buf[idx] + total, string + start, length); total += length; if (x < amount - 1) { memmove(buf[idx] + total, delim, dlen); total += dlen; }" TO g_FUNCTIONS
	WRITELN "string += (start + length); } __b2c__collapse = option; __b2c__SETLEN(buf[idx], total); buf[idx][total] = '\\0'; return(char*)(buf[idx]); }" TO g_FUNCTIONS
ENDIF

CLOSE FILE g_FUNCTIONS

' Check MEMORY/FREE
IF g_SEMANTIC = 0 THEN
	LOOKUP g_SEMANTIC_MEMFREE$ TO semantic$ SIZE COUNTER
	WHILE COUNTER > 0
		IF LEN(g_SEMANTIC_MEMFREE$(semantic$[COUNTER])) THEN EPRINT "WARNING: no FREE for the memory address ", g_SEMANTIC_MEMFREE$(semantic$[COUNTER]), "!"
		DECR COUNTER
	WEND
ENDIF

' Check OPEN/CLOSE handles
IF g_SEMANTIC = 0 THEN
	LOOKUP g_SEMANTIC_OPENCLOSE$ TO semantic$ SIZE COUNTER
	WHILE COUNTER > 0
		IF LEN(g_SEMANTIC_OPENCLOSE$(semantic$[COUNTER])) THEN EPRINT "WARNING: no CLOSE for the OPEN handle ", g_SEMANTIC_OPENCLOSE$(semantic$[COUNTER]), "!"
		DECR COUNTER
	WEND
ENDIF

' Show error in case function has no end
IF LEN(g_FUNCNAME$) THEN
	EPRINT "Syntax error: the SUB/FUNCTION '", g_FUNCNAME$, "' has no END in file '", g_CURFILE$, "'!"
	END 1
ENDIF

' Start indentation
IF ISTRUE(g_TMP_PRESERVE) THEN
	IF ISTRUE(LEN(EXEC$("which indent 2>/dev/null"))) THEN
		PRINT "Applying indentation... ";
		FOR tmpfile$ IN g_TMP_FILES$
			IF NOT(REGEX(tmpfile$, ".*\\.cpp")) AND NOT(REGEX(tmpfile$, ".*\\.tmp")) AND NOT(REGEX(tmpfile$, ".*\\.bac$")) AND NOT(REGEX(tmpfile$, ".*\\.lex$")) AND NOT(REGEX(tmpfile$, ".*\\.exe$")) THEN
				IF ISTRUE(INSTR(OS$, "Darwin")) OR ISTRUE(INSTR(OS$, "BSD")) THEN
					RENAME tmpfile$ TO tmpfile$ & ".BAK"
					SYSTEM "indent " & tmpfile$ & ".BAK " & tmpfile$
					DELETE FILE tmpfile$ & ".BAK"
				ELSE
					'SYSTEM "indent " & tmpfile$
					SYSTEM "indent -bad -bap -bli0 -cli4 -cbi0 -nbc -nbfda -nsc -nprs -bls -blf -lp -ts4 -ppi2 -npsl -i4 -il4 -l140 -nbbo " & tmpfile$
					DELETE FILE tmpfile$ & "~"
				END IF
			END IF
		NEXT
		PRINT "done."
	ELSE
		PRINT "WARNING: 'indent' not found on this system!"
		PRINT "Generated source code cannot be beautified."
	END IF
END IF

' Check if we need to run xgettext
IF g_XGETTEXT THEN
	IF ISTRUE(LEN(EXEC$("which xgettext 2>/dev/null"))) THEN
		PRINT "Executing xgettext... ";
		SYSTEM "xgettext --keyword=INTL" & g_STRINGSIGN$ & " --keyword=NNTL" & g_STRINGSIGN$ & ":1,2 -d " & BASENAME$(g_SOURCEFILE$, 1) & " -s -o " & BASENAME$(g_SOURCEFILE$, 1) & ".pot " & g_TMP_FILES$
		IF FILEEXISTS(BASENAME$(g_SOURCEFILE$, 1) & ".pot") THEN
			PRINT "done."
		ELSE
			PRINT "WARNING: catalog file not created!"
		END IF
	ELSE
		PRINT "WARNING: 'xgettext' not found on this system!"
	END IF
END IF

' Creation of the Makefile
OPEN g_TEMPDIR$ & "/Makefile.bacon" FOR WRITING AS makefile
WRITELN "# Created with BaCon ", g_VERSION$, " - (c) Peter van Eerten - MIT License", NL$ TO makefile
WRITELN BASENAME$(g_SOURCEFILE$, 1), g_BINEXT$, ": ", BASENAME$(g_SOURCEFILE$), ".o" TO makefile
WRITELN TAB$(1), g_CCNAME$, " -o ", BASENAME$(g_SOURCEFILE$, 1), g_BINEXT$, " ", BASENAME$(g_SOURCEFILE$), ".o ", g_LDFLAGS$, " ", g_LIB_TLS$, " -lm" TO makefile
WRITELN BASENAME$(g_SOURCEFILE$), ".o: ", BASENAME$(g_SOURCEFILE$), ".c" TO makefile
WRITELN TAB$(1), g_CCNAME$, " ", g_CCFLAGS$, " -c ", BASENAME$(g_SOURCEFILE$), ".c" TO makefile
WRITELN NL$, ".PHONY: clean" TO makefile
WRITELN "clean:" TO makefile
WRITELN TAB$(1), "rm -f *.o *.c ", BASENAME$(g_SOURCEFILE$, 1), g_BINEXT$, " ", BASENAME$(g_SOURCEFILE$, 1), ".*.* Makefile.bacon" TO makefile
CLOSE FILE makefile
g_TMP_FILES$ = g_TMP_FILES$ & " " & g_TEMPDIR$ & "/Makefile.bacon"

' Start compilation
IF ISFALSE(g_NO_COMPILE) THEN

	IF ISFALSE(LEN(EXEC$("which " & g_CCNAME$ & " 2>/dev/null"))) THEN
		EPRINT "ERROR: '", g_CCNAME$, "' not found on this system!"
		EPRINT "Generated source code cannot be compiled."
		END 0
	END IF
	PRINT "Compiling '", g_SOURCEFILE$, "'... ";

	' Make sure GCC uses English localization
	SETENVIRON "LANG", "C"

	old_curdir$ = CURDIR$
	CHANGEDIR g_TEMPDIR$
	SYSTEM "make -f Makefile.bacon 2>" & BASENAME$(g_SOURCEFILE$) & ".log"
	RETURN_CODE = RETVAL

	' Go back to working directory
	CHANGEDIR old_curdir$

	' Add temp file
	g_TMP_FILES$ = g_TMP_FILES$ & " " & g_TEMPDIR$ & "/" & BASENAME$(g_SOURCEFILE$) & ".log " & g_TEMPDIR$ & "/" & BASENAME$(g_SOURCEFILE$) & ".o"

	IF ISFALSE(FILELEN(g_TEMPDIR$ & "/" & BASENAME$(g_SOURCEFILE$) & ".log")) THEN
		PRINT "Done, program '", BASENAME$(g_SOURCEFILE$, 1), g_BINEXT$, "' ready."
	ELSE
		FOR line$ IN LOAD$(g_TEMPDIR$ & "/" & BASENAME$(g_SOURCEFILE$) & ".log") STEP NL$
			IF REGEX(line$, "\\.generic\\.h") THEN CONTINUE
			IF REGEX(line$, "error:|warning:|note:") THEN
				line$ = REPLACE$(line$, g_STRINGSIGN$, "$")
				line$ = REPLACE$(line$, g_FLOATSIGN$, "#")
				line$ = REPLACE$(line$, g_LONGSIGN$, "%")
				EPRINT line$
				BREAK
			ENDIF
		NEXT
		IF NOT(g_QUIET) THEN
			INPUT NL$, "INFO: see full error report (y/[n])? ", answer$
			IF LCASE$(answer$) = "y" THEN
				line$ = LOAD$(g_TEMPDIR$ & "/" & BASENAME$(g_SOURCEFILE$) & ".log")
				line$ = REPLACE$(line$, g_STRINGSIGN$, "$")
				line$ = REPLACE$(line$, g_FLOATSIGN$, "#")
				line$ = REPLACE$(line$, g_LONGSIGN$, "%")
				EPRINT line$
			ENDIF
		ENDIF

		' Preserve temp files
		g_TMP_PRESERVE = 1
	END IF
END IF

' Cleanup
IF ISFALSE(g_TMP_PRESERVE) THEN
	FOR tmpfile$ IN g_TMP_FILES$
		IF FILEEXISTS(tmpfile$) THEN
			IF NOT(REGEX(tmpfile$, ".bac$")) THEN DELETE FILE tmpfile$
		ELSE
			PRINT NL$, "WARNING: duplicate SUB or FUNCTION found! Temporary file ", tmpfile$, " already deleted."
		END IF
	NEXT
END IF

END RETURN_CODE
