/*	Copyright  (c)	Günter Woigk 2018 - 2018
					mailto:kio@little-bat.de

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

	Permission to use, copy, modify, distribute, and sell this software and
	its documentation for any purpose is hereby granted without fee, provided
	that the above copyright notice appear in all copies and that both that
	copyright notice and this permission notice appear in supporting
	documentation, and that the name of the copyright holder not be used
	in advertising or publicity pertaining to distribution of the software
	without specific, written prior permission.  The copyright holder makes no
	representations about the suitability of this software for any purpose.
	It is provided "as is" without express or implied warranty.

	THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
	INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
	EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
	CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
	DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
	TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
	PERFORMANCE OF THIS SOFTWARE.
*/

#include "Libraries/kio/kio.h"
#include "Libraries/unix/files.h"
#include "globals.h"
#include "Type.h"
#include "Names.h"
#include "Preprocessor/Word.h"
#include "utilities.h"
#include "FileInfo.h"

static const cstr stdnames[] =
{
	#define M(id,name) name
	#include "IdfID.h"
	#undef M
};

// Vcc itself:

	cstr	 appl_path;		// own path+name
	cstr	 appl_name;		// incantation: "vicci" or "vcc"
	time_t   appl_ctime;	// creation time of appl ((or install or modify))

// Vcc Options:

	int 	 optimize;		// 0,1,2 or 's'
	int 	 verbose;
	bool	 debug;

	cstr	 sourcefile;
	cstr	 sourcedir;
	cstr	 tempdir;		// "/tmp/vcc_"+tostr(cpu)
	cstr	 outputdir;		// "/my/project/dir/"
	cstr	 listdir;		// "/my/project/dir/listings/"
	StrArray librarypaths;
	StrArray includepaths;
	str		 argv_macros;	// command line macros, e.g. "foo=123" or "NDEBUG"

// State:

	// whole Job:
	cstr	 target_name;
	Target*	 target;
	Errors	 errors;

	// per compiled source file:
	Array<char>	source;		// source, incl. included files
	Names	 names(stdnames,NELEM(stdnames));	// name <-> idf
	Words	 words;			// tokenized source
	FileInfos included_files;// #included
	StrArray required_files; // #required

// Basic Types:
// all integer types are defined, even if the target does not support them
// floating point types are only defined if the target supports floating point numbers
	cBasicType* tint8	= nullptr;
	cBasicType* tuint8	= nullptr;
	cBasicType* tint16	= nullptr;
	cBasicType* tuint16	= nullptr;
	cBasicType* tint32	= nullptr;
	cBasicType* tuint32	= nullptr;
	cBasicType* tint64	= nullptr;
	cBasicType* tuint64	= nullptr;
	cBasicType* tvoid	= nullptr;
	cBasicType* tfloat	= nullptr;	// may be NULL
	cBasicType* tsfloat	= nullptr;	// may be NULL or same as tfloat
	cBasicType* tlfloat	= nullptr;	// may be NULL or same as tfloat

// Integer types supported by the target:
	cBasicType* tbyte	= nullptr;
	cBasicType* tubyte	= nullptr;
	cBasicType* tshort	= nullptr;
	cBasicType* tushort	= nullptr;
	cBasicType* tint 	= nullptr;
	cBasicType* tuint	= nullptr;
	cBasicType* tlong	= nullptr;
	cBasicType* tulong	= nullptr;

// Target Depending Sub Types:
	cPtrType*   tvoidptr = nullptr;	// ptr-size
	cEnumType*  tbool 	= nullptr;	// byte-size
	cEnumType*  tchar 	= nullptr;	// char-size
	cArrayType* tcstr 	= nullptr;	// array of tstrchar

void setTarget (cstr name) throws // AnyError
{
	if (eq(name,"vcc"))		// bytecode
	{
		#if defined(_I386)
			name = "i386";
		#elif defined(_I386x64)
			name = "i386x64";
		#elif defined(_POWERPC)
			name = "ppc";
		#else
			name = "undefined";	// don't know how to compile vcc bytecode for this machine
		#endif
	}

	delete target;	// if called again for next source file:
	if (!name) name = target_name;	// ""

	target_name = name;
	target = newTarget(name);

// Basic Types:
	tint8	= target->tint8;
	tuint8	= target->tuint8;
	tint16	= target->tint16;
	tuint16	= target->tuint16;
	tint32	= target->tint32;
	tuint32	= target->tuint32;
	tint64	= target->tint64;
	tuint64	= target->tuint64;
	tvoid	= target->tvoid;
	tfloat	= target->tfloat;		// may be NULL
	tsfloat	= target->tsfloat;		// may be NULL
	tlfloat	= target->tlfloat;		// may be NULL

// Target Depending Aliases:
	tbyte	 = target->tbyte;
	tubyte	 = target->tubyte;
	tshort	 = target->tshort;
	tushort	 = target->tushort;
	tint 	 = target->tint;
	tuint	 = target->tuint;
	tlong	 = target->tlong;
	tulong	 = target->tulong;

// Target Depending Types:
	tvoidptr = tvoid->ptrSubType();
	tbool	 = target->tbool;
	tchar	 = target->tchar;
	tcstr	 = tchar->arraySubType(0);	// TODO distinguish cstring vs. string aka char[]
}

void setTempDir(cstr s) throws // AnyError
{
	if(lastchar(s)!='/') s = catstr(s,"/");
	s = fullpath(s,1,1);
	if(errno) throw AnyError("create temp dir \"%s\" failed: %s",s,errorstr());
	if(!is_writable((s))) throw AnyError("directory \"%s\" is not writable",s);
	tempdir = s;
}

void setOutputDir(cstr s) throws // AnyError
{
	if(lastchar(s)!='/') s = catstr(s,"/");
	s = fullpath(s,1,1);
	if(errno) throw AnyError("create output dir \"%s\" failed: %s",s,errorstr());
	if(!is_writable((s))) throw AnyError("directory \"%s\" is not writable",s);
	outputdir  = s;
}

void setListDir(cstr s) throws // AnyError
{
	if(lastchar(s)!='/') s = catstr(s,"/");
	s = fullpath(s,1,1);
	if(errno) throw AnyError("create list dir \"%s\" failed: %s",s,errorstr());
	if(!is_writable((s))) throw AnyError("directory \"%s\" is not writable",s);
	listdir = s;
}

void addLibraryPath(cstr s) throws // AnyError
{
	if(lastchar(s)!='/') s = catstr(s,"/");
	s = fullpath(s,yes,no);
	if(errno) throw AnyError("access to library dir \"%s\" failed: %s",s,errorstr());
	librarypaths.append(s);
}

void addIncludePath(cstr s) throws // AnyError
{
	if(lastchar(s)!='/') s = catstr(s,"/");
	s = fullpath(s,yes,no);
	if(errno) throw AnyError("access to include dir \"%s\" failed: %s",s,errorstr());
	includepaths.append(s);
}

void setSourceFile(cstr s) throws // AnyError
{
	s = fullpath(s,yes,no);
	if (errno) throw AnyError("access to source file \"%s\" failed: %s",s,errorstr());
	if (!is_file((s))) throw AnyError("file \"%s\" is not a regular file",s);
	if (!is_readable((s))) throw AnyError("file \"%s\" is not readable",s);
	sourcefile = s;
	sourcedir = directory_from_path(s);
}
















