#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>

#include "header.h"

extern PROJLIST *projectList ;
extern char szInstallPath[] ;
extern HWND hwndError ;

extern HANDLE hInstance , hwndClient, hwndFrame ;

// ==============================================================
//
// property sheet constant names
//
#define PROPERTY_SHEET_COUNT 3
#define GENERALPROP 0
#define DEBUGPROP 1
#define TOOLOPTSPROP 2

static PROPSHEETPAGE pages[PROPERTY_SHEET_COUNT]; // the page structures
static PROPSHEETHEADER header;	// the header structure
static PROJLIST *proj ;

// ==============================================================
//
// routine to set the result from the killactive notify message

static void SetResult(HWND hwnd,int value)
{
	SetWindowLong(hwnd,DWL_MSGRESULT,value);
}
// ==============================================================
//
static int FAR PASCAL GeneralProc (HWND hwnd,UINT wmsg,WPARAM wparam,LPARAM lparam)

{
	NMHDR * nmhead;
	switch (wmsg) {
		case WM_INITDIALOG:
			return TRUE;
		case WM_NOTIFY:
			nmhead = (NMHDR *)lparam;
			switch (nmhead->code) {
				case PSN_SETACTIVE:
               /* page startup */           
               SendDlgItemMessage(hwnd,IDC_BUILDTYPE,CB_RESETCONTENT,0,0) ;
					NewFocus(hwnd,IDC_BUILDTYPE);
					SetEditField(hwnd,IDC_INCLUDEPATH,proj->includePath) ;
					SetEditField(hwnd,IDC_OUTPUTPATH,proj->outputPath) ;
               SetCBField(hwnd,IDC_DEBUGINFO,proj->buildFlags & BF_DEBUGINFO ? 1 : 0) ;
               SetCBField(hwnd,IDC_MAPFILE,proj->buildFlags & BF_MAPFILE ? 1 : 0) ;
               SetCBField(hwnd,IDC_COMPILEVIAASM,proj->buildFlags & BF_COMPILEVIAASM ? 1 : 0) ;
               SetCBField(hwnd,IDC_CHOSENPROJECT,proj->buildFlags & BF_CHOSENPROJECT ? 1 : 0) ;
					AddComboString(hwnd,IDC_BUILDTYPE,"Windows Console" );
					AddComboString(hwnd,IDC_BUILDTYPE,"Windows GUI" );
					AddComboString(hwnd,IDC_BUILDTYPE,"Windows DLL" );
					AddComboString(hwnd,IDC_BUILDTYPE,"Library" );
					AddComboString(hwnd,IDC_BUILDTYPE,"MSDOS" );
					SetComboSel(hwnd,IDC_BUILDTYPE,proj->buildType) ;
					break;
				case PSN_KILLACTIVE:
					/* verify ok always */
					SetResult(hwnd,FALSE);
					break;
				case PSN_APPLY:
					/* Page application */
					proj->buildType = GetComboSel(hwnd,IDC_BUILDTYPE) ;
					GetEditField(hwnd,IDC_INCLUDEPATH,proj->includePath) ;
					GetEditField(hwnd,IDC_OUTPUTPATH,proj->outputPath) ;
               proj->buildFlags &= ~(BF_DEBUGINFO | BF_MAPFILE | BF_COMPILEVIAASM | BF_CHOSENPROJECT) ;
               if (GetCBField(hwnd,IDC_DEBUGINFO))
                  proj->buildFlags |= BF_DEBUGINFO ;
               if (GetCBField(hwnd,IDC_MAPFILE))
                  proj->buildFlags |= BF_MAPFILE ;
               if (GetCBField(hwnd,IDC_COMPILEVIAASM))
                  proj->buildFlags |= BF_COMPILEVIAASM ;
               if (GetCBField(hwnd,IDC_CHOSENPROJECT)) {
                  PROJLIST *l = projectList ;
                  while (l) {
                        l->buildFlags &= ~BF_CHOSENPROJECT ;
                        l = l->next ;
                  }
                  proj->buildFlags |= BF_CHOSENPROJECT ;
               }
					break;
				case PSN_HELP:
					break;
			}
			break;
	}
	return FALSE;
}
// ==============================================================
//
static int FAR PASCAL DebugProc (HWND hwnd,UINT wmsg,WPARAM wparam,LPARAM lparam)

{
	NMHDR * nmhead;
   int disable_state  ;
	switch (wmsg) {
		case WM_INITDIALOG:
			return TRUE;
		case WM_NOTIFY:
			nmhead = (NMHDR *)lparam;
			switch (nmhead->code) {
				case PSN_SETACTIVE:
					/* page startup */
               disable_state = proj->buildType != BT_CONSOLE && proj->buildType != BT_WINDOWS ;
               DisableControl(hwnd,IDC_BREAKWINMAIN,disable_state) ;
               DisableControl(hwnd,IDC_BREAKDLL,disable_state) ;
               DisableControl(hwnd,IDC_DEBUGEXCEPTION,disable_state) ;
               DisableControl(hwnd,IDC_DEBUGTOOLTIPS,disable_state) ;
               DisableControl(hwnd,IDC_EDITCMDLINE,disable_state) ;
               NewFocus(hwnd,IDC_BREAKWINMAIN);
               SetCBField(hwnd,IDC_BREAKWINMAIN,proj->buildFlags & BF_BREAKWINMAIN ? 1 : 0) ;
               SetCBField(hwnd,IDC_BREAKDLL,proj->buildFlags & BF_BREAKDLL ? 1 : 0) ;
               SetCBField(hwnd,IDC_DEBUGEXCEPTION,proj->buildFlags & BF_DEBUGEXCEPTION ? 1 : 0) ;
               SetCBField(hwnd,IDC_DEBUGTOOLTIPS,proj->buildFlags & BF_DEBUGTOOLTIPS ? 1 : 0) ;
               SetEditField(hwnd,IDC_EDITCMDLINE,proj->cmdline) ;
					break;
				case PSN_KILLACTIVE:
					/* verify ok always */
					SetResult(hwnd,FALSE);
					break;
				case PSN_APPLY:
					/* Page application */
               proj->buildFlags &= ~(BF_BREAKWINMAIN | BF_BREAKDLL | BF_DEBUGEXCEPTION | BF_DEBUGTOOLTIPS) ;
               if (GetCBField(hwnd,IDC_BREAKWINMAIN))
                  proj->buildFlags |= BF_BREAKWINMAIN ;
               if (GetCBField(hwnd,IDC_BREAKDLL))
                  proj->buildFlags |= BF_BREAKDLL ;
               if (GetCBField(hwnd,IDC_DEBUGEXCEPTION))
                  proj->buildFlags |= BF_DEBUGEXCEPTION ;
               if (GetCBField(hwnd,IDC_DEBUGTOOLTIPS))
                  proj->buildFlags |= BF_DEBUGTOOLTIPS ;
               GetEditField(hwnd,IDC_EDITCMDLINE,proj->cmdline) ;
					break;
				case PSN_HELP:
					break;
			}
			break;
	}
	return FALSE;
}
// ==============================================================
//
static int FAR PASCAL TooloptProc (HWND hwnd,UINT wmsg,WPARAM wparam,LPARAM lparam)

{
	NMHDR * nmhead;
	switch (wmsg) {
		case WM_INITDIALOG:
			return TRUE;
		case WM_NOTIFY:
			nmhead = (NMHDR *)lparam;
			switch (nmhead->code) {
				case PSN_SETACTIVE:
					/* page startup */
               SetEditField(hwnd,IDC_TOCOMPILER,proj->compileopts) ;
               SetEditField(hwnd,IDC_TOASSEMBLER,proj->assembleopts) ;
               SetEditField(hwnd,IDC_TOLINKER,proj->linkopts) ;
               SetEditField(hwnd,IDC_TOLIBRARIAN,proj->libopts) ;
					break;
				case PSN_KILLACTIVE:
					/* verify ok always */
					SetResult(hwnd,FALSE);
					break;
				case PSN_APPLY:
					/* Page application */
               GetEditField(hwnd,IDC_TOCOMPILER,proj->compileopts) ;
               GetEditField(hwnd,IDC_TOASSEMBLER,proj->assembleopts) ;
               GetEditField(hwnd,IDC_TOLINKER,proj->linkopts) ;
               GetEditField(hwnd,IDC_TOLIBRARIAN,proj->libopts) ;
					break;
				case PSN_HELP:
					break;
			}
			break;
	}
	return FALSE;
}

// ==============================================================
//
// display the property sheet and return to caller
//
void TargetProperties(HINSTANCE hInst, HWND hwnd, PROJLIST *p)
{
	proj = p ;
	// struct for server page
	pages[GENERALPROP].dwSize = sizeof(PROPSHEETPAGE);
	pages[GENERALPROP].dwFlags = 0 /*PSP_HASHELP*/;
	pages[GENERALPROP].hInstance = hInst;
	pages[GENERALPROP].u.pszTemplate = "TARGETPROPDLG";
   pages[GENERALPROP].pfnDlgProc = GeneralProc;
	pages[GENERALPROP].pszTitle = "General" ;

   pages[DEBUGPROP].dwSize = sizeof(PROPSHEETPAGE);
   pages[DEBUGPROP].dwFlags = 0 /*PSP_HASHELP*/;
   pages[DEBUGPROP].hInstance = hInst;
   pages[DEBUGPROP].u.pszTemplate = "DEBUGPROPDLG";
   pages[DEBUGPROP].pfnDlgProc = DebugProc;
   pages[DEBUGPROP].pszTitle = "Debug" ;

   pages[TOOLOPTSPROP].dwSize = sizeof(PROPSHEETPAGE);
   pages[TOOLOPTSPROP].dwFlags = 0 /*PSP_HASHELP*/;
   pages[TOOLOPTSPROP].hInstance = hInst;
   pages[TOOLOPTSPROP].u.pszTemplate = "TOOLOPTPROPDLG";
   pages[TOOLOPTSPROP].pfnDlgProc = TooloptProc;
   pages[TOOLOPTSPROP].pszTitle = "Tool Options" ;

	// struct for property sheet header
	header.dwSize = sizeof(PROPSHEETHEADER);
	header.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_NOAPPLYNOW /* | PSH_HASHELP*/;
	header.hwndParent = hwnd;
	header.pszCaption = "Target";
	header.nPages = PROPERTY_SHEET_COUNT;
	header.u2.nStartPage = 0;
	header.u3.ppsp = &pages[0];

	// make the property sheet and exit
	PropertySheet(&header);
}

void newDepends(HWND tree, char *name, DEPENDSLIST *din, HTREEITEM item ,DEPENDSLIST **d)
{
	FILE *in = fopen(name,"r") ;
	if (!in)
		return ;
	if (din)
		din->treeHandle = TVInitInsert(tree,item,TVI_LAST,din->title) ;
	while (!feof(in)) {
		char buf[256],*p=buf ;
		buf[0] = 0 ;
		fgets(buf,256,in) ;
		while(*p && (*p == ' ' || *p == '\t'))
			p++ ;
		if (!strncmp(p,"#include",8) || !strncmp(p,"%include",8)) {
			p += 8 ;
			while(*p && (*p == ' ' || *p == '\t'))
				p++ ;
			if (*p == '"' || *p == '<') {
				p++ ;
				*d = malloc(sizeof(DEPENDSLIST)) ;
				if (*d) {
					int i = 0;
					memset(*d,0,sizeof(DEPENDSLIST)) ;
					while (*p && *p != '"' && *p != '>')
						(*d)->name[i++] = *p++ ;
					strcpy((*d)->title,(*d)->name) ;
					newDepends(tree, (*d)->name, (*d), item, &(*d)->next) ;
					while ((*d)->next)
						d = &(*d)->next ;
				}
			}
		}
	}
	fclose(in) ;
}
void CalcDepends(HWND tree, PROJLIST *proj)
{
	PROJLIST *l = proj ;
	while (l) {
		FILELIST *m = proj->files ;
		while (m) {
			DeleteDepends(m->depends) ;
			m->depends = 0 ;
			newDepends(tree,m->name,0,m->treeHandle,&m->depends) ;
			m = m->next ;
		}
		l = l->next ;
	}
}
void markProjects(int val)
{
	PROJLIST *l = projectList ;
	while (l) {
		FILELIST *m = l->files ;
		l->rebuild = val ;
		while (m) {
			m->rebuild = val ;
			m = m->next ;
		}
		l = l -> next ;
	}
}
int FileTime(FILETIME *timex, char *name)
{
	HANDLE fd ;
	BY_HANDLE_FILE_INFORMATION info ;
	
	fd = CreateFile(name,GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
	if (fd == INVALID_HANDLE_VALUE)
		return 0 ;	
	if (!GetFileTime(fd,0,0,timex)) {
	 	CloseHandle(fd) ;
		return 0 ;
	}
	CloseHandle(fd) ;
	return 1 ;
}
int CompareTimes(FILETIME *target, FILETIME *source)
{
	if (target->dwHighDateTime > source->dwHighDateTime)
		return 0 ;
	if (target->dwHighDateTime == source->dwHighDateTime)
		if (target->dwLowDateTime > source->dwLowDateTime)
			return 0 ;
	return 1 ;
}
int exists(char *name)
{
	FILE *in ;
	if (!name[0])
		return TRUE ;
	in = fopen(name,"r") ;
	if (in)
		fclose (in) ;
	return !!(int ) in ;
}
void OutputFile(PROJLIST *p, FILELIST *f, FILETIME *timex)
{
	char drive[10],dir[256],name[256],ext[100] ;
	if (p->outputPath[0]) {
		int l = strlen(p->outputPath) ;
		strcpy(f->output,p->outputPath) ;
		if (f->output[l-1] != '\\')
			strcat(f->output,"\\") ;
	} else {
		_splitpath(p->name,drive,dir,name,ext) ;
		strcpy(f->output,drive) ;
		strcat(f->output,dir) ;
	}
	_splitpath(f->name,drive,dir,name,ext) ;
	strcat(f->output,name) ;
	if (!xstricmpz(ext,".c") || !xstricmpz(ext,".cpp") || !xstricmpz(ext,".asm"))
		strcat(f->output,".obj") ;
	else if (!xstricmpz(ext,".rc"))
		strcat(f->output,".res") ;
	else
		strcat(f->output,ext) ;
	if (exists(f->output) && timex)
		FileTime(timex,f->output) ;

}
void CalcRebuilds(void)
{
	PROJLIST *l = projectList ;
	while (l) {
		FILELIST *m = l->files ;
		FileTime(&l->timex,l->name) ;
		while (m) {
			DEPENDSLIST *n = m->depends ;
			FileTime(&m->timex, m->name) ;
			OutputFile(l,m,&m->outputTimex) ;
			while (n) {
				FileTime(&n->timex, n->name) ;
				n = n->next ;
			}
			m = m->next ;
		}
		l = l -> next ;
	}
	l = projectList ;
	while (l) {
		FILELIST *m = l->files ;
		while (m) {
			DEPENDSLIST *n = m->depends ;
			while (n) {
				if (m->rebuild |= CompareTimes(&m->timex,&n->timex))
					break ;
				n = n->next ;
			}
			if (xstricmpz(m->output,m->name) && !exists(m->output) || CompareTimes(&m->outputTimex,&m->timex))
				m->rebuild = TRUE ;
			if (m->rebuild || CompareTimes(&l->timex, &m->timex))
				l->rebuild = TRUE ;
			m = m->next ;
		}
		l = l -> next ;
	}
}
int ParsePipeData(HANDLE handle)
{
	static char buf[513] ;
	static int pos = 0;
	char *p;
	int rv = TRUE ;
	while (TRUE) {
		int read = 0 ;
		if (pos < 512) 
			rv = ReadFile(handle,buf+pos,512-pos,&read,0) ;
		pos += read ;
		buf[pos] = 0 ;
		while(p = strchr(buf,'\n')) {
			char s = *++p ;
			*p = 0 ;
			SendMessage(hwndError,WM_SETTEXT,0,(LPARAM)buf) ;
			*p = s ;
			memcpy(buf,p,512-(p-buf)) ;
			pos -= p-buf ;
			buf[pos] = 0 ;
		}
		if (pos == 512 || !rv && pos) {
			buf[pos] = 0 ;
			SendMessage(hwndError,WM_SETTEXT,0,(LPARAM)buf) ;
			pos = 0 ;
		}			
		if (!read || !rv)
			break ;
	}
	return rv ;
}
int Execute(char *name, char *cmd)
{
   char filename[260] ;
	int retcode ;
   HANDLE stdoutWr,stdinRd ;
   HANDLE stdoutRd,stdinWr ;
   static char buf[1000] ;

//        HANDLE oldhand = GetStdHandle(STD_OUTPUT_HANDLE) ;
//        HANDLE oldhande = GetStdHandle(STD_ERROR_HANDLE) ;
//        HANDLE oldhandi = GetStdHandle(STD_INPUT_HANDLE) ;
	STARTUPINFO si ;
	PROCESS_INFORMATION pi ;
	SECURITY_ATTRIBUTES security ;

	memset(&security,0,sizeof(security)) ;
	security.nLength = sizeof(security) ;
	security.bInheritHandle = TRUE ;
   CreatePipe(&stdoutRd,&stdoutWr,&security,0) ;

	memset(&si,0,sizeof(si)) ;
	si.cb = sizeof(si) ;
        si.dwFlags=STARTF_USESTDHANDLES ;
//   SetStdHandle(STD_OUTPUT_HANDLE,stdoutWr) ;
//   SetStdHandle(STD_ERROR_HANDLE,stdoutWr) ;

   CreatePipe(&stdinRd, &stdinWr, &security,0) ;
   DuplicateHandle(GetCurrentProcess(),stdinWr,GetCurrentProcess(),&stdinWr,
                0,FALSE,DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE) ;
//   SetStdHandle(STD_INPUT_HANDLE,stdinRd) ;

   si.hStdInput = stdinRd ;
   si.hStdOutput = stdoutWr ;
   si.hStdError = stdoutWr;

   sprintf(filename, "%s\\bin\\%s",szInstallPath,name) ;
//    strcpy(filename,"par1.exe") ;
   retcode = CreateProcess(filename,cmd,0,0,1,DETACHED_PROCESS,0,0,&si,&pi) ;

//        SetStdHandle(STD_OUTPUT_HANDLE,oldhand) ;
//        SetStdHandle(STD_ERROR_HANDLE,oldhande) ;
//        SetStdHandle(STD_INPUT_HANDLE,oldhandi) ;

   CloseHandle(stdoutWr) ;
   CloseHandle(stdinRd) ;

   if (retcode) {
      sprintf(buf,"%s\r\n",cmd) ;   
      SendMessage(hwndError,WM_SETTEXT,0,(LPARAM) buf) ;
      while (ParsePipeData(stdoutRd)) ;
      WaitForSingleObject(pi.hProcess,INFINITE) ;
   }

   CloseHandle(stdoutRd) ;
   CloseHandle(stdinWr) ;

   if (!retcode)
      return 0x55555555;
   else {
      GetExitCodeProcess(pi.hProcess,&retcode ) ;
      CloseHandle(pi.hProcess) ;
      CloseHandle(pi.hThread) ;
   }
	return retcode ;
}
int CompileFile(PROJLIST *x, FILELIST *list)
{
	int rv ;
	char buffer[1000],*p ;
	char intermed[256] ;
   char * dbgFlag, *nasmFlag ;
	strcpy(intermed,list->output) ;
	p = strstr(intermed,".obj") ;
	
	if (p) {
      nasmFlag = (x->buildFlags & BF_COMPILEVIAASM) ? "/C+N " : "" ;
      dbgFlag = (x->buildFlags & BF_DEBUGINFO) ? "+v" : "" ;
      if (x->buildFlags & BF_COMPILEVIAASM)
         strcpy(p,".asm") ;                                 
      sprintf(buffer,"cc386 %s %s %s -I%s\\include",
            x->compileopts, nasmFlag, dbgFlag, szInstallPath) ;
		p = buffer + strlen(buffer) ;
		if (x->includePath[0])
			sprintf(p,";%s ",x->includePath) ;
		p += strlen(p) ;
		sprintf(p," -o%s %s",intermed,list->name) ;
		rv = Execute("cc386.exe",buffer) ;
		if (rv)
			return rv ;
      if (x->buildFlags & BF_COMPILEVIAASM) {
         sprintf(buffer,"nasm -fobj %s -o %s %s",x->assembleopts, list->output,intermed) ;
         return Execute("nasm.exe",buffer) ;
      } else
         return rv ;
	}
	return 1 ;
}
int AssembleFile(PROJLIST *x, FILELIST *list)
{
	char buffer[1000] ;
	sprintf(buffer,"nasm -fobj -o %s %s",list->output,list->name) ;
	return Execute("nasm.exe",buffer) ;
}
int RCFile(PROJLIST *x, FILELIST *list)
{
	char buffer[1000],*p=buffer ;
	sprintf(buffer,"xrc -r -fo%s -i%s\\include",list->output,szInstallPath) ;
	if (x->includePath[0]) {
		p += strlen(p) ;
		sprintf(p,";%s",x->includePath) ;
	}
	p += strlen(p );
	sprintf(p," %s",list->name) ;
	return Execute("xrc.exe",buffer) ;
}
int scanfiles(PROJLIST *list, char *p, char *ext)
{
	FILELIST *l= list->files ;
	int rv = 0 ;
	while (l) {
		char *x = strrchr(l->output,'.') ;
		if (x && !xstricmpz(x,ext)) {
			sprintf(p+rv,"%s ",l->output) ;
			rv+= strlen(p+rv) ;
		}
		l = l->next ;
	}
	return rv ;
}
int linkFile(PROJLIST *list)
{
	char buf[50000],*p ;
	char drive[10],dir[256],file[256],ext[256] ;
	_splitpath(list->name,drive,dir,file,ext) ;
   sprintf(buf,"valx %s -Nci -32 ", list->linkopts) ;
	p = buf + strlen(buf) ;
   if (list->buildFlags & BF_MAPFILE) {
      strcpy(p,"-MP ") ;
      p += strlen(p) ;
   }
   if (list->buildFlags & BF_DEBUGINFO) {
      strcpy(p,"-DEB ") ;
      p += strlen(p) ;
   }
	switch(list->buildType) {
		case BT_CONSOLE:
			sprintf(p,"-PE -CON %s\\lib\\c0xwin.obj ",szInstallPath) ;
			break ;
		case BT_WINDOWS:
			sprintf(p,"-PE -WIN %s\\lib\\c0win.obj ", szInstallPath) ;
			break ;
		case BT_DLL:
			sprintf(p,"-PE -BDL %s\\lib\\c0dwin.obj ", szInstallPath) ;
			break ;
		case BT_DOS:
			sprintf(p,"%s\\lib\\c0dos.obj ", szInstallPath) ;
			break ;
	}
	p += strlen(p) ;
	p+= scanfiles(list,p,".obj") ;
	*p++ = ',' ;
	strcpy(p,list->name) ;
	p += strlen(p) ;
	*p++ = ',' ;
   if (list->buildFlags & BF_MAPFILE) {
      strcpy(p,file);
      p += strlen(p) ;
   }
	*p++ = ',' ;
	p+= scanfiles(list,p,".lib") ;
	if (list->buildType == BT_DOS)
      sprintf(p,"%s\\lib\\cldos.lib", szInstallPath) ;
	else {
		sprintf(p,"%s\\lib\\clwin.lib %s\\lib\\climp.lib, ",szInstallPath,szInstallPath) ;
		p += strlen(p) ;
		p += scanfiles(list,p,".res") ;
		*p++=',' ;
		*p = 0;
	}
  return Execute("valx.exe",buf) ;
}
int libFile(PROJLIST *list) 
{
	char buffer[100000],*p ;
	unlink(list->name) ;
   sprintf(buffer,"xlib %s %s + ",list->name, list->libopts) ;
	p = buffer + strlen(buffer) ;
	scanfiles(list,p,".obj") ;
	return Execute("xlib.exe",buffer) ;
}
int buildFile(PROJLIST *l,FILELIST *list)
{
	char dirty[256],ext[100] ;
	_splitpath(list->name,dirty,dirty,dirty,ext) ;
	if (!xstricmpz(ext,".c") || !xstricmpz(ext,".cpp"))
		return CompileFile(l,list) ;
	else if (!xstricmpz(ext,".asm"))
		return AssembleFile(l,list) ;
	else if (!xstricmpz(ext,".rc"))
		return RCFile(l,list) ;
	else return !exists(list->output) ;
}
void MakerThread(void)
{
	PROJLIST *l = projectList ;
   int globalerr = FALSE ;
	SaveDrawAll() ;
	SendMessage(hwndError, WM_SETTEXT,0,0 ) ;
	ShowWindow(hwndError,SW_SHOW) ;
	SendMessage(hwndClient,WM_MDIACTIVATE,(WPARAM)hwndError,0) ;
	while (l) {
		if (l->rebuild) {
			FILELIST *m = l->files ;
			int dont = FALSE ;
			while (m) {
				if (m->rebuild) {
					dont |= buildFile(l,m) ;
					m->rebuild = FALSE ;
					
				}
				m = m->next ;
			}
			if (!dont) 
				if (l->buildType == BT_LIBRARY)
               dont |= libFile(l) ;
            else {
               dont |= linkFile(l) ;
            }
         globalerr |= dont ;
		}
		l = l->next ;
	}
   SendMessage(hwndError,WM_SETTEXT,0,(LPARAM)(globalerr ? "\r\nErrors Encountered.\r\n" : "\r\nDone.\r\n")) ;
}
static PROJLIST *compilerProjlist ;
static int compilerSel ;
void CompilerThread(void)
{
   FILELIST *m = compilerProjlist->files ;
	SaveDrawAll() ;
	SendMessage(hwndError, WM_SETTEXT,0,0 ) ;
	ShowWindow(hwndError,SW_SHOW) ;
	SendMessage(hwndClient,WM_MDIACTIVATE,(WPARAM)hwndError,0) ;
   while (--compilerSel)
		if (m)
			m = m->next ;
   OutputFile(compilerProjlist,m,0) ;
   buildFile(compilerProjlist,m) ;
	SendMessage(hwndError,WM_SETTEXT,0,(LPARAM)"\r\nDone.\r\n") ;
}
void Maker(void)
{
   DWORD threadhand ;
   CreateThread(0,0,(LPTHREAD_START_ROUTINE)MakerThread,0,0,&threadhand) ;
}
void Compiler(PROJLIST *l, int sel)
{
   DWORD threadhand ;
   compilerProjlist = l ;
   compilerSel = sel ;
   CreateThread(0,0,(LPTHREAD_START_ROUTINE)CompilerThread,0,0,&threadhand) ;
}