/* 
   Copyright 2001-2003 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   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.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222

**********************************************************************

MAKE.C holds the code for the compile and build operations.  IT also
holds the code for the properties dialog which is selected from the
project window right-click menu.

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

#include "header.h"

#define TEMPFILE "$$$CC386.TMP"

extern PROJLIST *projectList ;
extern char szInstallPath[] ;
extern HWND hwndError ;
extern int changedProject ;
extern int browseInfo ;
extern char szProjectName[256] ;

extern HANDLE hInstance , hwndClient, hwndFrame ;

static char tempfile[260];
static int errcount, warncount ;
// ==============================================================
//
// 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,relincludepath(proj->includePath)) ;
               SetEditField(hwnd,IDC_OUTPUTPATH,relpath(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) ;
               SetCBField(hwnd,IDC_CRTDLL,proj->buildFlags & BF_CRTDLL ? 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) ;
               if (proj->includePath[0] && proj->includePath[strlen(proj->includePath)-1] == '\\')
                  proj->includePath[strlen(proj->includePath)-1] = 0 ;
               if (proj->outputPath[0] && proj->outputPath[strlen(proj->outputPath)-1] == '\\')
                  proj->outputPath[strlen(proj->outputPath)-1] = 0 ;
               absincludepath(proj->includePath) ;
               abspath(proj->outputPath) ;
               proj->buildFlags &= ~(BF_DEBUGINFO | BF_MAPFILE | BF_COMPILEVIAASM | BF_CHOSENPROJECT | BF_CRTDLL) ;
               if (GetCBField(hwnd,IDC_CRTDLL))
                  proj->buildFlags |= BF_CRTDLL ;
               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 ;
               }
               changedProject = TRUE ;
					break;
				case PSN_HELP:
               ContextHelp(130) ;
					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) ;
               changedProject = TRUE ;
					break;
				case PSN_HELP:
               ContextHelp(130) ;
					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) ;
               changedProject = TRUE ;
					break;
				case PSN_HELP:
               ContextHelp(130) ;
					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 = 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 = 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 = 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.hInstance = hInstance ;
	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);
}

static void CreateTempFileName(void)
{
   GetTempPath(240,tempfile) ;
   if (tempfile[strlen(tempfile)-1] != '\\') ;
      strcat(tempfile,"\\") ;
   strcat(tempfile,TEMPFILE) ;
}
void newDepends(HWND tree, char *name, DEPENDSLIST *din, HTREEITEM item ,DEPENDSLIST **d)
{
	FILE *in = fopen(name,"r") ;
   char buf[256] ;
	if (!in)
		return ;
	if (din)
      din->treeHandle = TVInitInsert(tree,item,TVI_LAST,din->title,TRUE) ;
	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 == '<') {
            int i = 0;
            char *q,path[256] ;
            FILE *fil ;
				p++ ;
            strcpy(path,szProjectName) ;
            q = strrchr(path,'\\') ;
               if (q && *(q-1) != ':') {
                  *q = ';' ;
                  q++ ;
               } else
                  q = path ;
            strcpy(q,ProjectFindSelectedEXE()->includePath) ;
            while (*p && *p != '"' && *p != '>')
              buf[i++] = *p++ ;
            buf[i] = 0 ;
            if (fil = searchpath(buf,path,"r")) {
               fclose(fil) ;
               (*d) = malloc(sizeof(DEPENDSLIST)) ;
               if (*d) {
                  memset(*d,0,sizeof(DEPENDSLIST)) ;
                  strcpy((*d)->name,buf) ;
                  abspath((*d)->name) ; // in case it is in local dir
                  strcpy((*d)->title,buf) ;
                  newDepends(tree, (*d)->name, (*d), item, &(*d)->next) ;
                  while ((*d))
                    d = (*d) ;
               }
				}
			}
		}
	}
	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(&l->timex,&n->timex) || CompareTimes(&m->outputTimex,&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 ;
	}
}
void countErrors(char *buf)
{
   char *p = buf ;
   if (!xstricmp(p,"ERROR"))
      errcount++ ;
   if (!xstricmp(p,"WARNING"))
      warncount++ ;
   if (!xstricmp(p,"LINKER ERROR"))
      errcount++ ;
   if (!xstricmp(p,"FATAL ERROR"))
      errcount++ ;
   while (p = stristr(p,"\nERROR")) {
      errcount++ ;
      p+= 6 ;
   }
   p = buf ;
   while (p = stristr(p,"\nLINKER ERROR")) {
      errcount++ ;
      p+= 13 ;
   }
   p = buf ;
   while (p = stristr(p,"\nFATAL ERROR")) {
      errcount++ ;
      p+= 13 ;
   }
   p = buf ;
   while (p = stristr(p,"\nWARNING")) {
      warncount++ ;
      p+= 8 ;
   }
}
int ParsePipeData(HANDLE handle,int window)
{
	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,window,(LPARAM)buf) ;
         countErrors(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,window,(LPARAM)buf) ;
         countErrors(buf) ;
			pos = 0 ;
		}			
		if (!read || !rv)
			break ;
	}
	return rv ;
}
int Execute(char *name, char *cmd, int window)
{
   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 = INVALID_HANDLE_VALUE ;
   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,window,(LPARAM) buf) ;
      while (ParsePipeData(stdoutRd, window)) ;
      WaitForSingleObject(pi.hProcess,INFINITE) ;
   } else {
      sprintf(buf,"\r\nCan't spawn %s\r\n", filename) ;
      SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)buf) ;
   }

   CloseHandle(stdoutRd) ;
   CloseHandle(stdinWr) ;

   if (!retcode)
      return 0x55555555;
   else {
      GetExitCodeProcess(pi.hProcess,&retcode ) ;
      CloseHandle(pi.hProcess) ;
      CloseHandle(pi.hThread) ;
   }
	return retcode ;
}
void CompileMessage(char *title, char *name)
{
   char buf[256] ;
   sprintf(buf,"%s %s...\r\n",title,name) ;
   SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)buf) ;
}
int CompileFile(PROJLIST *x, FILELIST *list)
{
	int rv ;
   FILE *fil ;
	char buffer[1000],*p ;
	char intermed[256] ;
   char * dbgFlag, *nasmFlag,*browseFlag ;
	strcpy(intermed,list->output) ;
	p = strstr(intermed,".obj") ;


	if (p) {
      CompileMessage("Compiling",list->name) ;   
      nasmFlag = (x->buildFlags & BF_COMPILEVIAASM) ? "/C+N " : "/c" ;
      dbgFlag = (x->buildFlags & BF_DEBUGINFO) ? "+v" : "" ;
      browseFlag = (browseInfo) ? "/C+?" : "" ;
      if (x->buildFlags & BF_COMPILEVIAASM)
         strcpy(p,".asm") ;                                 
		if (x->includePath[0])
         sprintf(buffer,"%s %s %s %s \"-I%s\\include;%s\"",
            x->compileopts, nasmFlag, dbgFlag, browseFlag, szInstallPath,x->includePath) ;
      else
         sprintf(buffer,"%s %s %s %s \"-I%s\\include\"",
            x->compileopts, nasmFlag, dbgFlag, browseFlag, szInstallPath) ;
		p = buffer + strlen(buffer) ;
      sprintf(p," \"-o%s\" \"%s\"",intermed,list->name) ;
      fil = fopen(tempfile,"w") ;
      fprintf(fil,"%s",buffer) ;
      fclose(fil) ;
      sprintf(intermed,"cc386 /f%s",tempfile) ;
      rv = Execute("cc386.exe",intermed,ERR_BUILD_WINDOW) ;
      unlink(tempfile) ;
		if (rv)
			return rv ;
      if (x->buildFlags & BF_COMPILEVIAASM) {
         sprintf(buffer,"nasm -s -fobj %s -o \"%s\" \"%s\"",x->assembleopts, list->output,intermed) ;
         return Execute("nasm.exe",buffer,ERR_BUILD_WINDOW) ;
      } else
         return rv ;
	}
	return 1 ;
}
int AssembleFile(PROJLIST *x, FILELIST *list)
{
	char buffer[1000] ;
   CompileMessage("Assembling",list->name) ;   
   sprintf(buffer,"nasm -fobj -o \"%s\" \"%s\"",list->output,list->name) ;
   return Execute("nasm.exe",buffer,9) ;
}
int RCFile(PROJLIST *x, FILELIST *list)
{
	char buffer[1000],*p=buffer ;
   CompileMessage("Compiling Resources",list->name) ;   
   if (x->includePath[0])
      sprintf(buffer,"xrc -r \"-fo%s\" \"-i%s\\include;%s\"",list->output,szInstallPath,x->includePath) ;\
   else
      sprintf(buffer,"xrc -r \"-fo%s\" \"-i%s\\include\"",list->output,szInstallPath) ;
	p += strlen(p );
   sprintf(p," \"%s\"",list->name) ;
   return Execute("xrc.exe",buffer,ERR_BUILD_WINDOW) ;
}
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[100000],*p ;
	char drive[10],dir[256],file[256],ext[256] ;
   FILE *tempfil ;
   int rv ;
   SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)"Linking...\r\n") ;
   tempfil = fopen(tempfile,"w") ;
	_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",tempfile) ;
         fprintf(tempfil,"\"%s\\lib\\c0xwin.obj\" ",szInstallPath) ;
			break ;
		case BT_WINDOWS:
         sprintf(p,"-PE -WIN @%s",tempfile) ;
         fprintf(tempfil,"\"%s\\lib\\c0win.obj\" ",szInstallPath) ;
			break ;
		case BT_DLL:
         sprintf(p,"-PE -BDL @%s",tempfile) ;
         fprintf(tempfil,"\"%s\\lib\\c0dwin.obj\" ",szInstallPath) ;
			break ;
		case BT_DOS:
         sprintf(p,"@%s",tempfile) ;
         fprintf(tempfil,"\"%s\\lib\\c0dos.obj\" ",szInstallPath) ;
			break ;
	}
   p += strlen(p) + 1;
   p[0] = 0 ;
   scanfiles(list,p,".obj") ;
   fprintf(tempfil,"%s\n\"%s\"\n",p,list->name) ;
   if (list->buildFlags & BF_MAPFILE) {
      fprintf(tempfil,"\"%s\"\n",file) ;
   } else
      fprintf(tempfil,"\n") ;
   p[0] = 0 ;
   scanfiles(list,p,".lib") ;
   fprintf(tempfil,"%s",p) ;
	if (list->buildType == BT_DOS)
      fprintf(tempfil,"\"%s\\lib\\cldos.lib\"\n\n\n", szInstallPath) ;
	else {
      if (list->buildFlags & BF_CRTDLL)
         fprintf(tempfil,"\"%s\\lib\\climp.lib\" \"%s\\lib\\crtdll.lib\"\n",szInstallPath,szInstallPath) ;
      else
         fprintf(tempfil,"\"%s\\lib\\clwin.lib\" \"%s\\lib\\climp.lib\"\n",szInstallPath,szInstallPath) ;
         p[0] = 0 ;
      scanfiles(list,p,".res") ;
      if (*p)
         fprintf(tempfil,"%s\n\n",p) ;
      else
         fputc('\n',tempfil) ;
	}
   fclose(tempfil) ;
  rv =  Execute("valx.exe",buf,ERR_BUILD_WINDOW) ;
  unlink(tempfile) ;
  return rv ;
}
int browseFile(PROJLIST *list)
{
   FILE *tempfil ;
   int rv ;
   char buf[100000],*p=buf ;
   char filename[256],*q ;
   char cmd[256] ;
   strcpy(filename,szProjectName) ;
   q = strrchr(filename,'.') ;
   if (q)
      *q = 0 ;
   else {
      SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)"Internal Error...\r\n") ;
      return 1 ;
   }
   SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)"Creating Browse information...\r\n") ;
   scanfiles(list,p,".obj") ;
   tempfil = fopen(tempfile,"w") ;
   fputs(p,tempfil) ;
   fclose(tempfil) ;
   sprintf(cmd,"brc.exe \"%s\" @%s",filename,tempfile) ;
   rv = Execute("brc.exe",cmd,ERR_BUILD_WINDOW) ;
   fclose(tempfil) ;
   unlink(tempfile) ;
   SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)"Complete\r\n") ;
   return rv ;
}
int scanlibfiles(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\" &\n",l->output) ;
			rv+= strlen(p+rv) ;
		}
		l = l->next ;
	}
	return rv ;
}
int libFile(PROJLIST *list) 
{
	char buffer[100000],*p ;
   FILE *tempfil ;
   int rv ;
	unlink(list->name) ;
   SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)"Creating Library...") ;

   sprintf(buffer,"xlib \"%s\" %s @%s",list->name, list->libopts, tempfile) ;
	p = buffer + strlen(buffer) ;
   *p++= 0 ;
   scanlibfiles(list,p,".obj") ;
   tempfil = fopen(tempfile,"w") ;
   fputs(p,tempfil) ;
   fclose(tempfil) ;
   rv = Execute("xlib.exe",buffer,ERR_BUILD_WINDOW) ;
   unlink(tempfile) ;
   return rv ;
}
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) ;
}
ErrWarnCounts() 
{
   char buf[256] ;
   sprintf(buf,"\r\nCompile done.  Errors: %d,  Warnings: %d\r\n", errcount, warncount) ;
   SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)buf) ;
}
void MakerThread(void)
{
	PROJLIST *l = projectList ;
   int globalerr = FALSE ;
   CreateTempFileName() ;
   errcount = warncount = 0 ;
   SendMessage(hwndError, WM_SELERRWINDOW,0,ERR_BUILD_WINDOW) ;
   dmgrHideWindow(DID_ERRORWND, FALSE) ;
	SendMessage(hwndClient,WM_MDIACTIVATE,(WPARAM)hwndError,0) ;
   if (!l || !l->files) {
      SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)"Create a project and add targets before building") ;
      if (!l)
         ExtendedMessageBox("Build Error",0,"Before you can compile your files you need to create a project and add targets and source files") ;
      else
         ExtendedMessageBox("Build Error",0,"Before you can compile your files you need to source files to the project") ;
      return ;
   }      
	while (l) {
		if (l->rebuild) {
			FILELIST *m = l->files ;
			int dont = FALSE ;
         SendMessage(hwndError,WM_SETTEXT,ERR_BUILD_WINDOW,(LPARAM)"Compiling...\r\n") ;
			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 ;
	}
   TagLinesAdjust(0,FALSE,TRUE) ;
   ErrWarnCounts() ;
   if (!errcount && browseInfo) {
      FreeBrowseInfo() ;
      browseFile(projectList) ;
   }
   MessageBeep(MB_OK) ;
}
static PROJLIST *compilerProjlist ;
static int compilerSel ;
void CompilerThread(void)
{
   HWND win ;
   FILELIST *m = compilerProjlist->files ;
   CreateTempFileName() ;
   errcount = warncount = 0 ;
   if (IsWindow(win = (HWND) SendMessage(hwndClient,WM_MDIGETACTIVE,0,0)) && !IsSpecialWindow(win)) {
      DWINFO *ptr = (DWINFO *)GetWindowLong(win,0) ;
      if (SendMessage(ptr->dwHandle,EM_GETMODIFY,0,0))
         SendMessage(win,WM_COMMAND, IDM_SAVE,0) ;
   }
   SendMessage(hwndError, WM_SELERRWINDOW,0,ERR_BUILD_WINDOW) ;
   dmgrHideWindow(DID_ERRORWND, FALSE) ;
	SendMessage(hwndClient,WM_MDIACTIVATE,(WPARAM)hwndError,0) ;
   while (--compilerSel)
		if (m)
			m = m->next ;
   OutputFile(compilerProjlist,m,0) ;
   buildFile(compilerProjlist,m) ;
   ErrWarnCounts() ;
   MessageBeep(MB_OK) ;
}
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) ;
}