 
#ifdef MACVERSION
#include <standard.h>
#endif

#ifdef WIN95VERSION
#include "standard.h"
#endif

#include "memory.h"
#include "file.h"
#include "ops.h"
#include "strings.h"
#include "shellhooks.h"
#include "langexternal.h"
#include "langinternal.h"
#include "langtokens.h"
#include "tableinternal.h"
#include "tableverbs.h"
#include "tablestructure.h"
#include "resources.h"
#include "WinSockNetEvents.h"


#define str_isPike		"\x06" "isPike"
#define	str_isRadio		"\x07" "isRadio"
#define str_isMac		"\x05" "isMac"
#define str_isWindows	"\x09" "isWindows"
#define str_osFlavor	"\x08" "osFlavor"
#define str_osMajorVersion		"\x0e" "osMajorVersion"
#define str_osMinorVersion		"\x0e" "osMinorVersion"
#define str_osBuildNumber		"\x0d" "osBuildNumber"
#define str_osVersionString		"\x0f" "osVersionString"
#define str_osFullNameForDisplay	"\x14" "osFullNameForDisplay"
#define str_winServicePackNumber	"\x14" "winServicePackNumber"
#define str_isCarbon	"\x08" "isCarbon"
#define str_maxTcpConnections "\x11" "maxTcpConnections"


void initsegment (void) {
	
	} /*initsegment*/


static boolean newfunctionprocessor (bigstring bsname, langvaluecallback valuecallback, boolean flwindow, hdlhashtable *htable) {
	
	/*
	each of the external function processors register with the system by calling
	this routine.  we create a new hashtable in the EFP table, and return a
	handle to the new table.  we also link in a callback routine that processes the
	verbs for this EFP.  flwindow is also recorded -- it says whether or not
	the EFP requires a window be open in order for one of its verbs to be
	executed.
	
	6/1/93 dmb: flwindow parameter is now real. when true, the valuecallback must
	respond to being called with a nil parameter list by determining whether or not 
	a specific verb requires Frontier to be the current process.
	*/
	
	register hdlhashtable ht;
	
	if (!tablenewsystemtable (efptable, bsname, htable))
		return (false);
	
	ht = *htable; /*copy into register*/
	
	(**ht).flverbsrequirewindow = flwindow;
	
	(**ht).valueroutine = valuecallback;
	
	return (true);
	} /*newfunctionprocessor*/


static boolean hashinsertcstring (bigstring bs, const tyvaluerecord *v) {

	convertcstring (bs);

	return (hashinsert (bs, *v));
	} /*hashinsertcstring*/


static boolean langaddcstringkeyword (bigstring bs, short tokennumber) {
	
	tyvaluerecord val;
	
	initvalue (&val, tokenvaluetype);
	
	val.data.tokenvalue = (short) tokennumber;
	
	return (hashinsertcstring (bs, &val));
	} /*langaddcstringkeyword*/
	

static boolean langaddkeyword (bigstring bs, short tokennumber) {
	
	tyvaluerecord val;
	
	initvalue (&val, tokenvaluetype);
	
	val.data.tokenvalue = (short) tokennumber;
	
	return (hashinsert (bs, val));
	} /*langaddkeyword*/
	
/*
boolean langaddkeywordlist (hdlhashtable htable, byte * bskeywords[], short ctkeywords) {
	
	register short i;
	register boolean fl = true;
	
	pushhashtable (htable); 
	
	for (i = 0;  fl && (i < ctkeywords);  i++)
		fl = langaddkeyword ((ptrstring) bskeywords [i], i);
	
	pophashtable ();
	
	return (fl);
	} /*langaddkeywordlist*/


boolean loadfunctionprocessor (short id, langvaluecallback valuecallback) {
	
	/*
	2.1b5 dmb: having learning that our use of lots of string literals, and 
	hence the "Seperate STRS" option in Think C was making us victim of an 
	'040 instruction cache bug in Think C's run-time implementation of same, 
	it's time to create the kernel tables directly from resources.  that's 
	what this routine does.
	*/
	
	bigstring bsname;
	hdlhashtable htable;
	short flwindow;
	long ix = 0;
	Handle hefps;
	short ctefps;
	short ctverbs;
	short ixverb = 0;
	boolean fl = true;
	
#ifdef MACVERSION
	hefps = getresourcehandle ('EFP#', id);
#endif
#ifdef WIN95VERSION
	hefps = getresourcehandle ('EFP_', id);
#endif
	
	assert (hefps != nil);
	
	if (hefps == nil)
		return (false);
	
	if (!loadfromhandle (hefps, &ix, 2, &ctefps))
		return (false);
	
	while (--ctefps >= 0) {
		
		copyrezstring (*hefps + ix, bsname);
		
		ix += stringsize (bsname);
		
		if (!loadfromhandle (hefps, &ix, 2, &flwindow))
			return (false);
		
		if (!newfunctionprocessor (bsname, valuecallback, (boolean) flwindow, &htable))
			return (false);
		
		if (!loadfromhandle (hefps, &ix, 2, &ctverbs))
			return (false);
		
		pushhashtable (htable); 
		
		while (--ctverbs >= 0 && fl) {
			
			copyrezstring (*hefps + ix, bsname);
			
			ix += stringsize (bsname);
			
			fl = langaddkeyword ((ptrstring) bsname, ixverb++);
			}
		
		pophashtable ();
		}

	releaseresourcehandle (hefps);
	
	return (fl);
	} /*loadfunctionprocessor*/


static boolean initenvironment (hdlhashtable ht) {

	#ifdef MACVERSION
	
		bigstring bsversion;
		unsigned long x;
		
		gestalt (gestaltSystemVersion, &x);
		
		langassignbooleanvalue (ht, str_isMac, true);
		
		langassignbooleanvalue (ht, str_isWindows, false);
		
		//langassignstringvalue (ht, str_osFlavor, zerostring);
		
		langassignlongvalue (ht, str_osMajorVersion, x >> 8);
		
		langassignlongvalue (ht, str_osMinorVersion, (x & 0x00f0) >> 4);
		
		getsystemversionstring (bsversion, nil);
		
		langassignstringvalue (ht, str_osVersionString, bsversion);
		
		langassignstringvalue (ht, str_osFullNameForDisplay, "\x09" "Macintosh");

		
		#if TARGET_API_MAC_CARBON == 1 /*PBS 7.028: system.environment.isCarbon*/
		
			langassignbooleanvalue (ht, str_isCarbon, true);
			
		#else
			
			langassignbooleanvalue (ht, str_isCarbon, false);
			
		#endif
		
	#endif

	#ifdef WIN95VERSION
	
		bigstring bsversion, bsservicepack, bsos;
		byte bsflavor [4];
		OSVERSIONINFO osinfo;

		osinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
		
		GetVersionEx (&osinfo);
		
		copystring ("\x08" "Windows ", bsos);
		
		langassignbooleanvalue (ht, str_isMac, false);
		
		langassignbooleanvalue (ht, str_isWindows, true);
		
		if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
			copystring ("\x02" "NT", bsflavor);
		else {
			
			if (osinfo.dwBuildNumber == 0)
				copystring ("\x02" "95", bsflavor);
			else
				copystring ("\x02" "98", bsflavor);
			}
		
		pushstring (bsflavor, bsos);
		
		langassignstringvalue (ht, str_osFlavor, bsflavor);
		
		langassignlongvalue (ht, str_osMajorVersion, osinfo.dwMajorVersion);
		
		langassignlongvalue (ht, str_osMinorVersion, LOWORD(osinfo.dwMinorVersion));
		
		langassignlongvalue (ht, str_osBuildNumber, LOWORD(osinfo.dwBuildNumber));
		
		getsystemversionstring (bsversion, bsservicepack);
		
		langassignstringvalue (ht, str_osVersionString, bsversion);
		
		langassignstringvalue (ht, str_winServicePackNumber, bsservicepack);
		
		langassignstringvalue (ht, str_osFullNameForDisplay, bsos);
		
		langassignbooleanvalue (ht, str_isCarbon, false); /*7.0b28: isCarbon is false on Windows.*/

	#endif

	langassignlongvalue (ht, str_maxTcpConnections, maxconnections); /*7.0b37 PBS: max TCP connections*/
	
	#ifdef PIKE
		langassignbooleanvalue (ht, str_isPike, true);

		langassignbooleanvalue (ht, str_isRadio, true); /*7.0b37 PBS: system.environment.isRadio*/
		
	#else
		langassignbooleanvalue (ht, str_isPike, false);

		langassignbooleanvalue (ht, str_isRadio, false); /*7.0b37 PBS: system.environment.isRadio*/
	#endif

		return (true);
	} /*initenvironment*/


boolean inittablestructure (void) {
	
	/*
	do this just after you initialize lang.c.  
	
	we build the initial structure of hashtables for CanCoon.
	
	5.1.4 dmb: do the environmenttable
	*/
	
	hdlhashtable htable; 
	
	if (!newhashtable (&htable)) /*this is where everything starts*/
		return (false);
	
	pushhashtable (htable); /*set lang.c global*/
	
	// do the compiler table
	
	if (!tablenewsystemtable (htable, nameinternaltable, &internaltable))
		goto error;
	
	if (!tablenewsystemtable (internaltable, nameefptable, &efptable))
		goto error;
	
	if (!tablenewsystemtable (internaltable, namelangtable, &langtable))
		goto error;
	
	if (!tablenewsystemtable (internaltable, namestacktable, &runtimestacktable))
		goto error;
	
	if (!tablenewsystemtable (internaltable, namesemaphoretable, &semaphoretable))
		goto error;
	
	#if threadverbs
		if (!tablenewsystemtable (internaltable, namethreadtable, &threadtable))
			goto error;
	#endif
		
	#ifdef version42orgreater
		if (!tablenewsystemtable (internaltable, namefilewindowtable, &filewindowtable))
			goto error;
	#endif
	
	// now do the environment table
	
	if (!tablenewsystemtable (htable, nameenvironmenttable, &environmenttable))
		goto error;
	
	if (!initenvironment (environmenttable))
		goto error;
	
	pophashtable ();
	
	return (true);
	
	error:
	
	pophashtable ();
	
	disposehashtable (htable, false);
	
	internaltable = efptable = langtable = runtimestacktable = semaphoretable = threadtable = filewindowtable = environmenttable = nil;
	
	return (false);
	} /*inittablestructure*/


static boolean langaddnilconst (bigstring bs) {
	
	tyvaluerecord val;
	
	initvalue (&val, novaluetype);
	
	return (hashinsertcstring (bs, &val));
	} /*langaddnilconst*/


static boolean langaddlongconst (bigstring bs, long x) {
	
	tyvaluerecord val;
	
	setlongvalue (x, &val);
	
	return (hashinsertcstring (bs, &val));
	} /*langaddlongconst*/


static boolean langaddstringconst (bigstring bs, bigstring x) {
	
	tyvaluerecord val;
	
	setstringvalue (x, &val);
	
	if (!hashinsertcstring (bs, &val))
		return (false);
	
	exemptfromtmpstack (&val);
	
	return (true);
	} /*langaddstringconst*/


static boolean langaddintconst (bigstring bs, short x) {
	
	tyvaluerecord val;
	
	setintvalue (x, &val);
	
	return (hashinsertcstring (bs, &val));
	} /*langaddintconst*/
	

static boolean langadddirectionconst (bigstring bs, tydirection x) {
	
	tyvaluerecord val;
	
	setdirectionvalue (x, &val);
	
	return (hashinsertcstring (bs, &val));
	} /*langadddirectionconst*/


static boolean langaddbooleanconst (bigstring bs, boolean x) {
	
	tyvaluerecord val;
	
	setbooleanvalue (x, &val);
	
	return (hashinsert (bs, val));
	} /*langaddintconst*/


static boolean langaddtypeconst (bigstring bs, tyvaluetype x) {
	
	tyvaluerecord val;
	
	setostypevalue (langgettypeid (x), &val);
	
	return (hashinsert (bs, val));
	} /*langaddtypeconst*/


#define add(x,y) if (!langaddcstringkeyword ((ptrstring) x, y)) return (false)

#define addnil(x) if (!langaddnilconst ((ptrstring) x)) return (false)

#define addlong(x,y) if (!langaddlongconst ((ptrstring) x, y)) return (false)

#define addint(x,y) if (!langaddintconst ((ptrstring) x, y)) return (false)

#define adddirection(x,y) if (!langadddirectionconst ((ptrstring) x, y)) return (false)

#define addboolean(x,y) if (!langaddbooleanconst ((ptrstring) x, y)) return (false)

#define addtype(x,y) if (!langaddtypeconst ((ptrstring) x, y)) return (false)

#define addstring(x,y) if (!langaddstringconst ((ptrstring) x, y)) return (false)


static boolean langinitconsttable (void) {
	
	/*
	2.1b1 dmb: added shortType as a special case; redundant with intType, 
	but more consistent with user termiology
	
	2.1b2 dmb: added nil constant
	*/
	
	tyvaluetype type;
	bigstring bs;
	
	if (!tablenewsystemtable (langtable, (ptrstring) "\x09" "constants", &hconsttable))
		return (false);
		
	pushhashtable (hconsttable); /*converted to constants by the scanner*/
	
	addnil ("nil");
	
	addlong ("infinity", longinfinity);
	
	adddirection ("up", up);
	
	adddirection ("down", down);
	
	adddirection ("left", left);
	
	adddirection ("right", right);
	
	adddirection ("flatup", flatup);
	
	adddirection ("flatdown", flatdown);
	
	adddirection ("nodirection", nodirection);
	
	adddirection ("pageup", pageup);
	
	adddirection ("pagedown", pagedown);
	
	adddirection ("pageleft", pageleft);
	
	adddirection ("pageright", pageright);
	
	addboolean (bstrue, (boolean) true);
	
	addboolean (bsfalse, (boolean) false);
	
	for (type = novaluetype; type < ctvaluetypes; type++)
		
		switch (type) {
			
			case olddoublevaluetype: /*don't define constants for these types*/
			case externalvaluetype:
			
			#ifndef fliowa
			
			case headvaluetype:
			
			#endif
			
			case oldstringvaluetype: /*8/13*/
			case passwordvaluetype: /*9/17*/
			case unused2valuetype:
				break;
			
			default:
				langgettypestring (type, bs);
				
				lastword (bs, chspace, bs);
				
				pushstring ((ptrstring) "\x04Type", bs);
				
				addtype (bs, type);
				
				break;
			}
	
	addtype ("\x09shortType", intvaluetype); /*special case to match coercion verb*/
	
	addstring ("machinePPC", machinePPC);
	addstring ("machine68K", machine68K);
	addstring ("machineX86", machinex86);
	
	addstring ("osMacOS", osMacOS);
	//Code change by Timothy Paustian Tuesday, July 11, 2000 9:41:39 PM
	//We add a detection for the carbon environment
	addstring("osMacCn", osCarbon);
	addstring ("osWin95", osWin95);
	addstring ("osWinNT", osWinNT);
	
	pophashtable ();
	
	return (true);
	} /*langinitconsttable*/


static boolean langinitbuiltintable (void) {
	
	if (!tablenewsystemtable (langtable, (ptrstring) "\x08" "builtins", &hbuiltinfunctions))
		return (false);
	
	pushhashtable (hbuiltinfunctions); /*converted to function ops by the parser*/
	
	add ("appleevent", appleeventfunc);
	
	add ("complexevent", complexeventfunc);
	
	add ("finderevent", findereventfunc);
	
	add ("tableevent", tableeventfunc);
	
	add ("objspec", objspecfunc);
	
	add ("setobj", setobjspecfunc);
	
	add ("pack", packfunc);
	
	add ("unpack", unpackfunc);
	
	add ("defined", definedfunc);
	
	add ("typeof", typeoffunc);
	
	add ("sizeof", sizeoffunc);
	
	add ("nameof", nameoffunc);
	
	add ("parentof", parentoffunc);

	add ("indexof", indexoffunc);
	
	add ("gestalt", gestaltfunc);
	
	add ("syscrash", syscrashfunc);
	
	#if !flruntime
	
	add ("myMoof", myMooffunc);
	
	#endif
	
	pophashtable ();
	
	return (true);
	} /*langinitbuiltintable*/


static boolean langinitkeywordtable (void) {
	
	/*
	3/6/92 dmb: added "with" token
	*/
	
	if (!tablenewsystemtable (langtable, (ptrstring) "\x08" "keywords", &hkeywordtable))
		return (false);
	
	pushhashtable (hkeywordtable); /*converted to tokens by the scanner*/
	
	add ("equals", equalsfunc);
	
	add ("notequals", notequalsfunc);
	
	add ("greaterthan", greaterthanfunc);
	
	add ("lessthan", lessthanfunc);
	
	add ("not", notfunc);
	
	add ("and", andfunc);
	
	add ("or", orfunc);
	
	add ("beginswith", beginswithfunc);
	
	add ("endswith", endswithfunc);
	
	add ("contains", containsfunc);
	
	add ("loop", loopfunc);
	
	add ("fileloop", fileloopfunc);
	
	add ("while", whilefunc);
	
	add ("in", infunc);
	
	add ("break", breakfunc);
	
	add ("continue", continuefunc);
	
	add ("return", returnfunc);
	
	add ("if", iffunc);
	
	add ("then", thenfunc);
	
	add ("else", elsefunc);
	
	add ("bundle", bundlefunc);
	
	add ("local", localfunc);
	
	add ("on", onfunc);
	
	add ("case", casefunc);
	
	add ("kernel", kernelfunc);
	
	add ("for", forfunc);
	
	add ("to", tofunc);
	
	add ("downto", downtofunc);
	
	add ("with", withfunc);
	
	add ("try", tryfunc);
	
	pophashtable ();
	
	return (true);
	} /*langinitkeywordtable*/


static boolean langinstallresources (void) {
	
	if (!langinitconsttable ())
		return (false);
	
	if (!langinitbuiltintable ())
		return (false);
	
	if (!langinitkeywordtable ())
		return (false);
	
	return (true);
	} /*langinstallresources*/


boolean langinitverbs (void) {
	
	if (!langinstallresources ())
		return (false);
	
	return (langinitbuiltins ());
	} /*langinitverbs*/

boolean initlang (void) {

	shellpushmemoryhook (&hashflushcache);
	
	langcallbacks.symbolchangedcallback = (langsymbolchangedcallback) &truenoop; 
	
	langcallbacks.symbolunlinkingcallback = (langtablenodecallback) &truenoop;
	
	langcallbacks.symboldeletedcallback = (langaddresscallback) &truenoop;
	
	langcallbacks.symbolinsertedcallback = (langsymbolinsertedcallback) &truenoop;
	
	langcallbacks.comparenodescallback = (langcomparenodescallback) &falsenoop;
		
	langcallbacks.debuggercallback = (langtreenodecallback) &truenoop;
	
	langcallbacks.debugerrormessagecallback = (langerrormessagecallback) &truenoop;
	
	langcallbacks.scriptkilledcallback = (langbooleancallback) &falsenoop;
	
	newclearhandle (longsizeof (tyerrorstack), (Handle *) &langcallbacks.scripterrorstack);
	
	/* 4.1b4 dmb: no longer push this be default. langrun now does it.
	langpusherrorcallback (nil, 0L);
	*/
	
	/*
	langcallbacks.scripterrorcallback = &truenoop;
	
	langcallbacks.scripterrorrefcon = (long) 0;
	*/
	
	langcallbacks.scriptcompilecallback = (langhashnodetreenodecallback) &falsenoop;
	
	langcallbacks.backgroundtaskcallback = (langbooleancallback) &truenoop;
	
	langcallbacks.pushtablecallback = (langtablerefcallback) &langdefaultpushtable;
	
	langcallbacks.poptablecallback = (langtablecallback) &langdefaultpoptable;
	
	langcallbacks.pushsourcecodecallback = (langsourcecodecallback) &truenoop;
	
	langcallbacks.popsourcecodecallback = (langvoidcallback) &truenoop;
	
	langcallbacks.saveglobalscallback = (langvoidcallback) &truenoop;
	
	langcallbacks.restoreglobalscallback = (langvoidcallback) &truenoop;
	
	langcallbacks.errormessagecallback = (langerrormessagecallback) &truenoop;
	
	langcallbacks.errormessagerefcon = nil;
	
	langcallbacks.clearerrorcallback = (langvoidcallback) &truenoop;
	
	langcallbacks.msgverbcallback = (langverbcallback) &truenoop;
	
	langcallbacks.codereplacedcallback = (langtreenodescallback) &truenoop;
	
	langcallbacks.idvaluecallback = nil;
	
	langcallbacks.partialeventloopcallback = (langshortcallback) &falsenoop;
	
	langcallbacks.processeventcallback = (langeventcallback) &falsenoop; /*4.1b13 dmb - new*/
	
	if (!newclearhandle (longsizeof (tytablestack), (Handle *) &hashtablestack))
		return (false);
	
	return (true);
	} /*initlang*/


