/* 
CCIDE
Copyright 2001-2011 David Lindauer.

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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

You may contact the author at:
	mailto::camille@bluegrass.net
 */
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>

#include "header.h"

#define TEMPFILE "$$$CC386.TMP"

extern int browsing;
extern HWND hwndToolDebug;
extern PROJLIST *projectList;
extern char szInstallPath[];
extern int changedProject;
extern int browseInfo;
extern enum DebugState uState;
extern char szWorkspaceName[];
extern HANDLE hInstance, hwndClient, hwndFrame;

int making, stopBuild;
int errcount, warncount;

static char tempfile[260];

void IsMaking(int makeRunning)
{
    making = makeRunning;
    SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);

} 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, DEPENDSLIST *root, PROJLIST *proj)
{
    DEPENDSLIST *temp = root;
    char buf2[280];
	BOOL rcFile = FALSE;
    FILE *in = fopen(name, "r");
    if (!in)
        return ;
	if (!stricmp(name + strlen(name) - 3, ".rc"))
	{
		rcFile = TRUE;
	}
    //   if (din)
    //      din->treeHandle = TVInitInsert(tree,item,TVI_LAST,din->title,TRUE) ;
    while (!feof(in))
    {
        char buf[1024],  *p = buf;
        buf[0] = 0;
        fgets(buf, 1024, in);
        while (*p && (*p == ' ' ||  *p == '\t'))
            p++;
        if (*p == '#')
        {
            p++;
            while (*p && (*p == ' ' ||  *p == '\t'))
                p++;
            if (!strncmp(p, "include", 7))
            {
                p += 7;
                while (*p && (*p == ' ' ||  *p == '\t'))
                    p++;
                if (*p == '"' ||  *p == '<')
                {
                    int i = 0;
                    char *q, path[256];
                    FILE *fil;
                    p++;
                    strcpy(path, proj->projectName);
                    q = strrchr(path, '\\');
                    if (q && *(q - 1) != ':')
                    {
                        *q = ';';
                        q++;
                    }
                    else
                        q = path;
                    strcpy(q, proj->includePath);
                    while (*p &&  *p != '"' &&  *p != '>')
                        buf[i++] =  *p++;
                    buf[i] = 0;
                    if (fil = searchPathI(buf, path, "r"))
                    {
                        fclose(fil);
                        if ((q = strchr(buf, '\\')) && q[ - 1] != '.')
                            strcpy(buf, relpath(buf, proj->projectName));
                        strcpy(buf2, buf);
                        abspath(buf2, proj->projectName); // in case it is in local dir
                        temp = root;
                        while (temp)
                        {
                            if (!stricmp(temp->name, buf2))
                                break;
                            temp = temp->next;
                        }
                        if (!temp)
                        {
                            (*d) = calloc(1,sizeof(DEPENDSLIST));
                            if (*d)
                            {
                                memset(*d, 0, sizeof(DEPENDSLIST));
                                strcpy((*d)->name, buf2);
								q = strrchr(buf,'\\');
								if (q)
									q++;
								else
									q = buf;
                                strcpy((*d)->title, q);
                                newDepends(tree, (*d)->name, (*d), item, &(*d)
                                    ->next, root, proj);
                                while ((*d))
                                    d = (*d);
                            }
                        }
                    }
                }
            }
        }
		else if (rcFile)
		{
			static char *names[] = {
				"cursor", "font" ,"bitmap" ,"icon", "messagetable", "rcdata"
			};
			int i;
			char *q = NULL;
			for (i= 0; i < sizeof(names)/sizeof(names[0]); i++)
			{
				if (q = stristr(p, names[i]))
				{
					if (q == p || isspace(q[-1]))
					{
						q += strlen(names[i]);
						if (isspace(*q))
						{
							p = q;
							while (isspace(*p)) p++;
								
			                if (*p == '"' ||  *p == '<')
			                {
			                    int i = 0;
			                    char path[256];
			                    FILE *fil;
			                    p++;
			                    strcpy(path, proj->projectName);
			                    q = strrchr(path, '\\');
			                    if (q && *(q - 1) != ':')
			                    {
			                        *q = ';';
			                        q++;
			                    }
			                    else
			                        q = path;
			                    strcpy(q, proj->includePath);
			                    while (*p &&  *p != '"' &&  *p != '>')
			                        buf[i++] =  *p++;
			                    buf[i] = 0;
			                    if (fil = searchPathI(buf, path, "r"))
			                    {
			                        fclose(fil);
			                        if ((q = strchr(buf, '\\')) && q[ - 1] != '.')
			                            strcpy(buf, relpath(buf, proj->projectName));
			                        strcpy(buf2, buf);
			                        abspath(buf2, proj->projectName); // in case it is in local dir
			                        temp = root;
			                        while (temp)
			                        {
			                            if (!stricmp(temp->name, buf2))
			                                break;
			                            temp = temp->next;
			                        }
			                        if (!temp)
			                        {
			                            (*d) = calloc(1,sizeof(DEPENDSLIST));
			                            if (*d)
			                            {
			                                memset(*d, 0, sizeof(DEPENDSLIST));
			                                strcpy((*d)->name, buf2);
											q = strrchr(buf,'\\');
											if (q)
												q++;
											else
												q = buf;
			                                strcpy((*d)->title, q);
			                                newDepends(tree, (*d)->name, (*d), item, &(*d)
			                                    ->next, root, proj);
			                                while ((*d))
			                                    d = (*d);
			                            }
			                        }
			                    }
							}
							break;
						}
					}
				}
			}
		}
    }
    fclose(in);
}

//-------------------------------------------------------------------------

void CalcDepends(HWND tree, PROJLIST *proj)
{
    PROJLIST *l = proj;
    int count = 0, prog = 0;
    FILELIST *m = proj->sourceFiles;
    while (m)
    {
        count++;
        m = m->next;
    }
    m = proj->resourceFiles;
    while (m)
    {
        if (!stristr(m->name,".rc")) 
            count++;
        m = m->next;
    }
    if (count == 0)
    {
        ExtendedMessageBox("Dependencies", MB_SETFOREGROUND |
            MB_SYSTEMMODAL, "No files in target");
        RefreshDepends(tree, l);
        return ;
    }
    changedProject = TRUE;
	proj->changed = TRUE;
    SetBusy(1);
    MakeProgress(0, hInstance, "Dependency Calculation Progress", count);
    m = proj->sourceFiles;
    while (m)
    {
        SetProgress(prog++, "File %d of %d", prog, count);
        DeleteDepends(m->depends);
        m->depends = 0;
        newDepends(tree, m->name, 0, m->treeHandle, &m->depends, &m->depends, proj);
        m = m->next;
    }
    m = proj->resourceFiles;
    while (m)
    {
        if (stristr(m->name,".rc")) 
        {
            count++;
            DeleteDepends(m->depends);
            m->depends = 0;
            newDepends(tree, m->name, 0, m->treeHandle, &m->depends, &m->depends, proj);
        }
        m = m->next;
    }
    SetProgress(prog++, "File %d of %d", count, count);
    RefreshDepends(tree, l);
    TreeView_Expand(tree, l->includeTreeHandle, TVE_EXPAND);
    TreeView_Expand(tree, l->treeHandle, TVE_EXPAND);
    DeleteProgress();
    SetBusy(0);
}

//-------------------------------------------------------------------------

void MarkProject( PROJLIST *l, int val)
{
    FILELIST *m = l->sourceFiles;
    l->rebuild = val;
    while (m)
    {
        DEPENDSLIST *n = m->depends;
        while (n)
        {
            n->rebuild = val;
            n = n->next;
        }
        m->rebuild = val;
        m = m->next;
    }
	m = l->resourceFiles;
    while (m)
    {
        DEPENDSLIST *n = m->depends;
        while (n)
        {
            n->rebuild = val;
            n = n->next;
        }
        m->rebuild = val;
        m = m->next;
    }
}
void markProjects(int val)
{
    PROJLIST *l = projectList;
    while (l)
    {
		MarkProject(l, val);
        l = l->next;
    }
}

//-------------------------------------------------------------------------

int FileTime(FILETIME *timex, char *name)
{
    HANDLE fd;

	memset(timex, 0, sizeof(*timex));
    fd = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, 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)
{
    // gotta have a two second delay because windows writes the files
    // in different orders... this is the max delay based on FAT
    DWORD high = source->dwHighDateTime - target->dwHighDateTime;
    int carry = source->dwLowDateTime < target->dwLowDateTime;
    DWORD low = source->dwLowDateTime - target->dwLowDateTime;
    high -= carry;
    carry = (low - 20000001) > low;
    low -= 20000001;
    high -= carry;
    if ((int)high >= 0)
        return 1;
    return 0;
}

//-------------------------------------------------------------------------

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);
	if (p->buildType == BT_LIBRARY)
	{
		char buf[260], *p;
		strcpy(buf, dir);
		p = buf;
		while (*p)
		{
			if (!isalnum(*p))
				*p = '_';
			p++;
		}
		strcat(f->output, buf);
		strcat(f->output, "_");
		strcat(f->output, name);
	}
	else
	    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 repDependsTime(char *name, FILETIME *time)
{
    PROJLIST *l = projectList;
    while (l)
    {
        FILELIST *m = l->sourceFiles;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            while (n)
            {
                if (!stricmp(name, n->name))
                {
                    n->timex =  *time;
                    n->gottime = TRUE;
                }
                n = n->next;
            }
            m = m->next;
        }
        m = l->resourceFiles;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            while (n)
            {
                if (!stricmp(name, n->name))
                {
                    n->timex =  *time;
                    n->gottime = TRUE;
                }
                n = n->next;
            }
            m = m->next;
        }
        l = l->next;
    }
}

//-------------------------------------------------------------------------

int CalcRebuilds(void)
{
    PROJLIST *l = projectList;
    int rv = FALSE;
    SetBusy(1);
    while (l)
	{
        FILELIST *m = l->sourceFiles;
        FileTime(&l->timex, l->name);
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            while (n)
            {
                n->gottime = FALSE;
                n = n->next;
            }
            m = m->next;
        }
        m = l->resourceFiles ;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            while (n)
            {
                n->gottime = FALSE;
                n = n->next;
            }
            m = m->next;
        }
        l = l->next;
    }
    l = projectList;
    while (l)
    {
        FILELIST *m = l->sourceFiles;
        FileTime(&l->timex, l->name);
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            FileTime(&m->timex, m->name);
            OutputFile(l, m, &m->outputTimex);
            while (n)
            {
                if (!n->gottime)
                {
                    FileTime(&n->timex, n->name);
                    repDependsTime(n->name, &n->timex);
                }
                n = n->next;
            }
            m = m->next;
        }
        m = l->resourceFiles;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
            FileTime(&m->timex, m->name);
            OutputFile(l, m, &m->outputTimex);
            while (n)
            {
                if (!n->gottime)
                {
                    FileTime(&n->timex, n->name);
                    repDependsTime(n->name, &n->timex);
                }
                n = n->next;
            }
            m = m->next;
        }
        m = l->otherFiles;
        while (m)
        {
            FileTime(&m->timex, m->name);
			strcpy(m->output, m->name);
            m = m->next;
        }
        l = l->next;
    }
    l = projectList;
    while (l)
    {
        FILELIST *m = l->sourceFiles;
		if (!exists(l->name))
			rv = l->rebuild = TRUE;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
			rv |= l->rebuild |= CompareTimes(&l->timex, &m->outputTimex);
            while (n)
            {
                l->rebuild |= CompareTimes(&l->timex, &n->timex);
                n->rebuild = CompareTimes(&m->outputTimex, &n->timex);
                if (n->rebuild)
                {
                    //               ExtendedMessageBox("hi",MB_SETFOREGROUND | MB_SYSTEMMODAL,"%s %s %s",l->title,m->output,n->title) ;
                }
                m->rebuild |= n->rebuild;
                n = n->next;
            }
            if (xstricmpz(m->output, m->name) && !exists(m->output) ||
                CompareTimes(&m->outputTimex, &m->timex))
            {
                m->rebuild = TRUE;
                //            ExtendedMessageBox("hi",MB_SETFOREGROUND | MB_SYSTEMMODAL,"%s %s",m->title,m->output) ;
                rv = TRUE;
            }
            if (m->rebuild || CompareTimes(&l->timex, &m->timex))
            {
                l->rebuild = TRUE;
                //            ExtendedMessageBox("hi",MB_SETFOREGROUND | MB_SYSTEMMODAL,"%s %s",l->title,m->title) ;
                rv = TRUE;
            }
            m = m->next;
        }
        m = l->resourceFiles;
        while (m)
        {
            DEPENDSLIST *n = m->depends;
			l->rebuild |= CompareTimes(&l->timex, &m->outputTimex);
            while (n)
            {
                l->rebuild |= CompareTimes(&l->timex, &n->timex);
                n->rebuild = CompareTimes(&m->outputTimex, &n->timex);
                if (n->rebuild)
                {
                    //               ExtendedMessageBox("hi",MB_SETFOREGROUND | MB_SYSTEMMODAL,"%s %s %s",l->title,m->output,n->title) ;
                }
                m->rebuild |= n->rebuild;
                n = n->next;
            }
            if (xstricmpz(m->output, m->name) && !exists(m->output) ||
                CompareTimes(&m->outputTimex, &m->timex))
            {
                m->rebuild = TRUE;
                //            ExtendedMessageBox("hi",MB_SETFOREGROUND | MB_SYSTEMMODAL,"%s %s",m->title,m->output) ;
                rv = TRUE;
            }
            if (m->rebuild || CompareTimes(&l->timex, &m->timex))
            {
                l->rebuild = TRUE;
                //            ExtendedMessageBox("hi",MB_SETFOREGROUND | MB_SYSTEMMODAL,"%s %s",l->title,m->title) ;
                rv = TRUE;
            }
            m = m->next;
        }
        m = l->otherFiles;
        while (m)
        {
			rv |= l->rebuild |= CompareTimes(&l->timex, &m->timex);
            m = m->next;
        }
        l = l->next;
    }
    l = projectList;
    while (l)
    {
		int len = strlen(l->name);
		if (len >= 4)
		{
			if (!stricmp(l->name + len - 4, ".lib") ||
				!stricmp(l->name + len - 4, ".dll"))
			{
				if (l->rebuild)
				{
					PROJLIST *l1 = projectList;
					while (l1)
					{
						l1->rebuild = TRUE;
						l1 = l1->next;
					}
					break ;
				}
			}
		}
		l = l->next;
	}
    SetBusy(0);
    return rv;
}

//-------------------------------------------------------------------------

void countErrors(char *buf)
{
    char *p = buf;
    if (!xstricmp(p, "ERROR") || stristr(p, "ERROR:"))
        errcount++;
    if (!xstricmp(p, "WARNING") || stristr(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, HANDLE hProcess)
{
    static char buf[513];
    static int pos = 0;
    char *p;
    int rv = TRUE;
    while (TRUE)
    {
        int read = 0;
        if (pos < 512)
        {
            int avail = 0;
            DWORD xx;
            avail = 0;
			while (!avail)
			{
            	rv = PeekNamedPipe(handle, 0, 0, 0, &avail, 0);
				if (!rv || !avail)
				{
	                GetExitCodeProcess(hProcess, &xx);
	                if (xx != STILL_ACTIVE)
	                {
	                    break;
	                }
					Sleep(10);
				}
			}
            if (avail)
            {
                rv = ReadFile(handle, buf + pos, 512-pos, &read, 0);
            }
        }
        pos += read;
        buf[pos] = 0;
        while (p = strchr(buf, '\n'))
        {
            char s =  *++p;
			int wc = warncount, ec = errcount;
            *p = 0;
            countErrors(buf);
			if (ec != errcount)
				SetErrorColor(window, 0x0000ff); // red
			else if (wc != warncount)
				SetErrorColor(window, 0xff0000); // blue
			SendErrorMessage(window, buf);
            *p = s;
            memcpy(buf, p, 512-(p - buf));
            pos -= p - buf;
            buf[pos] = 0;
        }
        if (pos == 512 || !rv && pos)
        {
			int wc = warncount, ec = errcount;
            buf[pos] = 0;
            countErrors(buf);
			if (ec != errcount)
				SetErrorColor(window, 0x0000ff); // red
			else if (wc != warncount)
				SetErrorColor(window, 0xff0000); // blue
			SendErrorMessage(window, buf);
            pos = 0;
        }
        if (!read || !rv)
            break;
    }
    return rv;
}

//-------------------------------------------------------------------------

int Execute(char *name, char *cmd, char *wdp, int window)
{
    char filename[260];
    char cmdbuf[1024];
	char path[260], *p;
    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;

	// set up the working dir for the tool
	strcpy(path, wdp);
	p = strrchr(path, '\\');
	if (p && p[-1] != ':')
	{
		*p = 0;
	}
		
    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;

    if (!name)
    {
        sprintf(cmdbuf, "\"%s\" /C %s", getenv("COMSPEC"), cmd);
        retcode = CreateProcess(0, cmdbuf, 0, 0, 1, DETACHED_PROCESS |
            CREATE_SUSPENDED, 0, path, &si, &pi);
    }
    else
    {
        sprintf(filename, "%s\\bin\\%s", szInstallPath, name);
        retcode = CreateProcess(filename, cmd, 0, 0, 1, DETACHED_PROCESS |
            CREATE_SUSPENDED, 0, path, &si, &pi);
    }

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

    CloseHandle(stdoutWr);
    CloseHandle(stdinRd);


    if (retcode)
    {
		int prio = GetThreadPriority(GetCurrentThread());
		SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
        SetPriorityClass(pi.hProcess, NORMAL_PRIORITY_CLASS);
        SetThreadPriority(pi.hThread, THREAD_PRIORITY_HIGHEST);
        ResumeThread(pi.hThread);
        while (ParsePipeData(stdoutRd, window, pi.hProcess))
            ;
        WaitForSingleObject(pi.hProcess, INFINITE);
        while (ParsePipeData(stdoutRd, window, pi.hProcess))
            ;
		SetThreadPriority(GetCurrentThread(), prio);
    }
    else
    {
        sprintf(buf, "\r\n%d: Can't spawn %s\r\n", GetLastError(), filename);
		SendErrorMessage(window, 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);
	SendErrorMessage(ERR_BUILD_WINDOW, (LPARAM)buf);
}

//-------------------------------------------------------------------------

void repdefines(PROJLIST *x, char *buffer)
{
    DEFINES *d = x->defines;
    while (d)
    {
        strcat(buffer, " ");
        buffer += strlen(buffer);
        sprintf(buffer, "-D%s", d->name);
        if (d->value[0])
        {
            buffer += strlen(buffer);
            sprintf(buffer, "=%s", d->value);
        }
        d = d->next;
    }
}

//-------------------------------------------------------------------------

int CompileFile(PROJLIST *x, FILELIST *list)
{
    int rv;
    FILE *fil;
    char buffer[10000],  *p;
    char intermed[10000];
    char working[300];
    char *dbgFlag,  *nasmFlag,  *browseFlag,  *nasmdebugFlag,  *warningFlag, 
        *c99Flag, *ansiFlag, *alignFlag;
	char buildType, importType;
    char projectPath[260];
    strcpy(projectPath, x->projectName);
    p = strrchr(projectPath, '\\');
    if (p)
        *(p + 1) = 0;
    strcpy(intermed, list->output);
    p = strstr(intermed, ".obj");


    if (p)
    {
        CompileMessage("Compiling", list->title);
        nasmFlag = (x->buildFlags &BF_COMPILEVIAASM) ? "/C+N " : "/c";
        dbgFlag = (x->buildFlags &BF_DEBUGINFO) ? "+v" : "";
        nasmdebugFlag = (x->buildFlags &BF_DEBUGINFO) ? "-Fls -g" : "";
        browseFlag = (browseInfo) ? "/C+?" : "";
        warningFlag = (x->buildFlags &BF_SHOWWARNINGS) ? "" : "/w-all";
        c99Flag = (x->buildFlags &BF_C99) ? "/9" : "";
        ansiFlag = (x->buildFlags &BF_ANSI) ? "+A" : "";
		switch (x->buildType)
		{
			case BT_CONSOLE:
				buildType = 'c';
				break;
			case BT_WINDOWS:
				buildType = 'g';
				break;
			case BT_DLL:
				buildType = 'd';
				break;
			default:
				buildType = 'c';
				break;
		}
		switch (x->libType)
		{
			case LT_LSCRTDLL:
				importType = 'l';
				break;
			case LT_MSVCRT:
				importType = 'm';
				break;
			case LT_CRTDLL:
				importType = 'c';
				break;
			default:
				if (x->buildType == BT_DOS)
					importType = 'A';
				else
					importType = ' ';
				break;
		}
		alignFlag = (x->buildFlags &BF_ALIGNSTACK) ? "/C+s" : "";
		
        if (x->buildFlags &BF_COMPILEVIAASM)
            strcpy(p, ".asm");
        if (x->includePath[0])
            sprintf(buffer, "/W%c%c %s %s %s %s %s %s %s %s \"-I%s\\include;%s;%s\"",
                buildType, importType, x->compileopts, nasmFlag, dbgFlag, browseFlag, warningFlag,
                c99Flag, ansiFlag, alignFlag, szInstallPath, projectPath, x->includePath);
        else
            sprintf(buffer, "/W%c%c %s %s %s %s %s %s %s %s \"-I%s\\include;%s\"", 
				buildType, importType, 
				x->compileopts, nasmFlag, dbgFlag, browseFlag, warningFlag,
                c99Flag, ansiFlag, alignFlag, szInstallPath, projectPath);
        repdefines(x, buffer);
        p = buffer + strlen(buffer);
        sprintf(p, " \"-o%s\" \"%s\"", intermed, list->name);
        fil = fopen(tempfile, "w");
        fprintf(fil, "%s", buffer);
        fclose(fil);
        sprintf(working, "cc386 \"/f%s\"", tempfile);
        rv = Execute("cc386.exe", working, x->projectName, ERR_BUILD_WINDOW);
        unlink(tempfile);
        if (rv)
            return rv;
        if (x->buildFlags &BF_COMPILEVIAASM)
        {
            buffer[0] = 0;
            repdefines(x, buffer);
            sprintf(buffer + strlen(buffer), " -s -fobj %s", nasmdebugFlag);
            fil = fopen(tempfile, "w");
            fprintf(fil, "%s", buffer);
            fclose(fil);
            sprintf(working, "nasm \"@%s\" -o \"%s\" \"%s\"", tempfile, list
                ->output, intermed);
            rv = Execute("nasm.exe", working, x->projectName, ERR_BUILD_WINDOW);
            unlink(tempfile);
            return rv;
        }
        else
            return rv;
    }
    return 1;
}

//-------------------------------------------------------------------------

int AssembleFile(PROJLIST *x, FILELIST *list)
{
    char buffer[10000];
    char working[300];
    FILE *fil;
    int rv;
    char *nasmdebugFlag = (x->buildFlags &BF_DEBUGINFO) ? "-Fls -g" : "";
    CompileMessage("Assembling", list->title);
    buffer[0] = 0;
    repdefines(x, buffer);
    sprintf(buffer + strlen(buffer), " -s -fobj %s", nasmdebugFlag);
    fil = fopen(tempfile, "w");
    fprintf(fil, "%s", buffer);
    fclose(fil);
    sprintf(working, "nasm \"@%s\" -o \"%s\" \"%s\"", tempfile, list->output, list
        ->name);
    rv = Execute("nasm.exe", working, x->projectName, ERR_BUILD_WINDOW);
    unlink(tempfile);
    return rv;

}

//-------------------------------------------------------------------------

int RCFile(PROJLIST *x, FILELIST *list)
{
    char buffer[10000];
    char working[300];
    char projectPath[260],  *p;
    FILE *fil;
    int rv;
    strcpy(projectPath, x->projectName);
    p = strrchr(projectPath, '\\');
    if (p)
        *(p + 1) = 0;
    CompileMessage("Compiling Resources", list->title);
    buffer[0] = 0;
    repdefines(x, buffer);
    if (x->includePath[0])
        sprintf(buffer + strlen(buffer), " -r \"-i%s\\include;%s;%s\"",
            szInstallPath, projectPath, x->includePath);
    else
        sprintf(buffer + strlen(buffer), " -r \"-i%s\\include;%s\"",
            szInstallPath, projectPath);
    fil = fopen(tempfile, "w");
    fprintf(fil, "%s", buffer);
    fclose(fil);
    sprintf(working, "xrc \"@%s\" \"-fo%s\" \"%s\"", tempfile, list->output, list
        ->name);
    rv = Execute("xrc.exe", working, x->projectName, ERR_BUILD_WINDOW);
    unlink(tempfile);
    return rv;
}

//-------------------------------------------------------------------------

int scanfiles(PROJLIST *list, FILELIST *l, char *p, char *ext)
{
    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;
	PROJLIST *projList = projectList;
	
    CompileMessage("Linking", "");
    tempfil = fopen(tempfile, "w");
    _splitpath(list->name, drive, dir, file, ext);
    sprintf(buf, "valx -Nci -32 ");
    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);
            if (list->libType != LT_NONE)
                if (list->libType == LT_LSCRTDLL)
                    fprintf(tempfil, "\"%s\\lib\\c0xdll.obj\" ", szInstallPath);
                else
                    fprintf(tempfil, "\"%s\\lib\\c0xwin.obj\" ", szInstallPath);
            break;
        case BT_WINDOWS:
            sprintf(p, "-PE -WIN @'%s'", tempfile);
            if (list->libType != LT_NONE)
                if (list->libType == LT_LSCRTDLL)
                    fprintf(tempfil, "\"%s\\lib\\c0dll.obj\" ", szInstallPath);
                else
                    fprintf(tempfil, "\"%s\\lib\\c0win.obj\" ", szInstallPath);
            break;
        case BT_DLL:
            sprintf(p, "-PE -BDL @'%s'", tempfile);
            if (list->libType != LT_NONE)
                if (list->libType == LT_LSCRTDLL)
                    fprintf(tempfil, "\"%s\\lib\\c0ddll.obj\" ", szInstallPath);
                else
                    fprintf(tempfil, "\"%s\\lib\\c0dwin.obj\" ", szInstallPath);
            break;
        case BT_DOS:
            sprintf(p, "-LE @'%s'", tempfile);
            if (list->libType != LT_NONE)
                fprintf(tempfil, "\"%s\\lib\\c0dosw.obj\" ", szInstallPath);
            break;
        case BT_RAW:
            sprintf(p, "-SYS @'%s'", tempfile);
//            if (list->libType != LT_NONE)
 //               fprintf(tempfil, "\"%s\\lib\\c0dosw.obj\" ", szInstallPath);
            break;
    }
    p += strlen(p) + 1;
    p[0] = 0;
    scanfiles(list, list->sourceFiles, p, ".obj");
    fprintf(tempfil, "%s %s\n\"%s\"\n", list->linkopts, p, list->name);
    if (list->buildFlags &BF_MAPFILE)
    {
        fprintf(tempfil, "\"%s\"\n", file);
    }
    else
        fprintf(tempfil, "\n");
	while (projList)
	{
		int len = strlen(projList->name);
		if (len >= 4)
		{
			if (!stricmp(projList->name + len -4, ".lib"))
			{
				fprintf(tempfil,"\"%s\" ",projList->name);
			}
		}	
		projList = projList->next;
	}
    p[0] = 0;
    scanfiles(list, list->otherFiles, p, ".lib");
    fprintf(tempfil, "%s ", p);
    if (list->buildType == BT_DOS || list->buildType == BT_RAW)
        if (list->libType == LT_STANDARD)
            fprintf(tempfil, "\"%s\\lib\\cldos.lib\"\n\n\n", szInstallPath);
        else
            fprintf(tempfil, "\n\n\n");
    else
    {
		if (list->libType == LT_MSVCRT)
                fprintf(tempfil, 
                    "\"%s\\lib\\climp.lib\" \"%s\\lib\\msvcrt.lib\"\n",
                    szInstallPath, szInstallPath);
        else if (list->libType == LT_CRTDLL)
                fprintf(tempfil, 
                    "\"%s\\lib\\climp.lib\" \"%s\\lib\\crtdll.lib\"\n",
                    szInstallPath, szInstallPath);
            else if (list->libType == LT_STANDARD)
                fprintf(tempfil, 
                    "\"%s\\lib\\clwin.lib\" \"%s\\lib\\climp.lib\"\n",
                    szInstallPath, szInstallPath);
            else if (list->libType == LT_LSCRTDLL)
                fprintf(tempfil, 
                    "\"%s\\lib\\lscrtl.lib\" \"%s\\lib\\climp.lib\"\n",
                    szInstallPath, szInstallPath);
            else
                fprintf(tempfil, "\"%s\\lib\\climp.lib\"\n", szInstallPath);
        p[0] = 0;
        scanfiles(list, list->resourceFiles, p, ".res");
        if (*p)
            fprintf(tempfil, "%s\n\n\n", p);
        else
            fprintf(tempfil, "\n\n\n");
    }
    fclose(tempfil);
    rv = Execute("valx.exe", buf, list->name, 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, szWorkspaceName);
    q = strrchr(filename, '.');
    if (q)
        *q = 0;
    else
    {
		SendErrorMessage(ERR_BUILD_WINDOW, "Internal Error...\r\n");
        return 1;
    }
    CompileMessage("Creating Browse Information", "");
	
    tempfil = fopen(tempfile, "w");
	while (list)
	{
	    scanfiles(list, list->sourceFiles, p, ".obj");
	    fputs(p, tempfil);
		list = list->next ;
	}
    fclose(tempfil);
    sprintf(cmd, "brc.exe \"%s\" \"@%s\"", filename, tempfile);
    rv = Execute("brc.exe", cmd, szWorkspaceName, ERR_BUILD_WINDOW);
    fclose(tempfil);
    unlink(tempfile);
    SendErrorMessage(ERR_BUILD_WINDOW, "Build Complete\r\n");
    return rv;
}

//-------------------------------------------------------------------------

int scanlibfiles(PROJLIST *list, char *p, char *ext)
{
    FILELIST *l = list->sourceFiles;
    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);
    CompileMessage("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, list->projectName, 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);
}

//-------------------------------------------------------------------------

void ReplaceWildcards(PROJLIST *l, char *buf, char *steps)
{
    while (*steps)
    {
        if (*steps == '$' && *(steps + 1) == '(')
        {
            int skip = 0;
            char data[MAX_PATH];
            data[0] = 0;
            if (!strncmp(steps + 2, "OUTPUTDIR", 9))
            {
                skip = 12;
                if (l->outputPath[0])
                    strcpy(data, l->outputPath);
                else
                {
                    char *p;
                    strcpy(data, l->projectName);
                    p = strrchr(data, '\\');
                    if (p)
                    {
                        if (p[ - 1] == ':')
                            p[1] = 0;
                        else
                            p[0] = 0;
                    }
                }
            }
            else if (!strncmp(steps + 2, "INSTALLDIR", 10))
            {
                skip = 13;
                strcpy(data, szInstallPath);
            }
            else if (!strncmp(steps + 2, "SYSTEMDIR", 9))
            {
                skip = 12;
                GetSystemDirectory(data, MAX_PATH);
            }
            else if (!strncmp(steps + 2, "WINDIR", 6))
            {
                skip = 9;
                GetWindowsDirectory(data, MAX_PATH);
            }
            else if (!strncmp(steps + 2, "TARGETDIR", 10))
            {
                char *p;
                skip = 13;
                strcpy(data, l->projectName);
                p = strrchr(data, '\\');
                if (p)
                    if (p[ - 1] == ':')
                        p[1] = 0;
                    else
                        p[0] = 0;
            }
            else
            {
                char *n = strchr(steps, ')');
                if (n)
                {
                    int len = n - steps - 2;
                    strncpy(data, steps + 2, len);
                    data[len] = 0;
                    n = getenv(data);
                    if (n)
                    {
                        strcpy(data, n);
                        skip = len + 3;
                    }
                }
            }
            if (!skip || steps[skip - 1] != ')')
                *buf++ =  *steps++;
            else
            {
                *buf++ = '"';
                strcpy(buf, data);
                buf += strlen(buf);
                steps += skip;
                while (*steps && (isalnum(*steps) ||  *steps == '\\' ||  *steps
                    == '.'))
                    *buf++ =  *steps++;
                *buf++ = '"';
            }

        }
        else
        {
            *buf++ =  *steps++;
        }
    }
    *buf = 0;
}

//-------------------------------------------------------------------------

int PrePost(PROJLIST *l, char *tag, char *label, char *steps)
{
    char buf[1024];
    char buf1[1024];
    if (steps[0])
    {
        CompileMessage(tag, label);
        while (1)
        {
            char *p = buf;
            while (*steps &&  *steps != '\n')
                if (*steps == '\r')
                    steps++;
                else
                    *p++ =  *steps++;
            *p = 0;
            ReplaceWildcards(l, buf1, buf);
            if (Execute(0, buf1, l->projectName, ERR_BUILD_WINDOW))
            {
                CompileMessage(tag, "Error processing");
                errcount++;
                return TRUE;
            }
            if (! *steps)
                break;
            else
                steps++;
        }
    }
    return FALSE;
}

//-------------------------------------------------------------------------

void ErrWarnCounts()
{
    char buf[256];
    sprintf(buf, "\r\nCompile done.  Errors: %d,  Warnings: %d\r\n", errcount,
        warncount);
	if (errcount)
		SetErrorColor(ERR_BUILD_WINDOW, 0x0000ff); // red
	else if (warncount)
		SetErrorColor(ERR_BUILD_WINDOW, 0xff0000); // blue
	SendErrorMessage(ERR_BUILD_WINDOW, buf);
}

//-------------------------------------------------------------------------

int MakerThread(int type)
{
    PROJLIST *l = projectList, *selectedProject = NULL;
    int rv, i;
    int globalerr = FALSE;
	if (type == IDM_BUILDSELECTED) 
	{
		selectedProject = ProjectFindSelectedEXE(0);
		if (!selectedProject)
		{
            ExtendedMessageBox("Build Error", MB_SETFOREGROUND | MB_SYSTEMMODAL,
                "No target is selected");
	        return 0 ;
		}
	}
    IsMaking(TRUE);
    CreateTempFileName();
	
    errcount = warncount = 0;
    dmgrHideWindow(DID_ERRORWND, FALSE);
	SelectErrorWindow(ERR_BUILD_WINDOW);
    if (!l || !l->sourceFiles)
    {
        SendErrorMessage(ERR_BUILD_WINDOW, "Create a workspace and add targets before building");
        if (!l)
            ExtendedMessageBox("Build Error", MB_SETFOREGROUND | MB_SYSTEMMODAL,
                "Before you can compile your files you need to create a workspace and add targets and source files");
        else
            ExtendedMessageBox("Build Error", MB_SETFOREGROUND | MB_SYSTEMMODAL,
                "Before you can compile your files you need to add source files to the workspace");
        IsMaking(FALSE);
        return 0 ;
    }
    SaveDrawAll();
    markProjects(0);
    rv = CalcRebuilds();
	if (type == IDM_BUILDSELECTED)
	{
		MarkProject(selectedProject,1);
	}
    else if (type == IDM_BUILDALL)
	{
        markProjects(1);
	}
    else if (!rv)
    {
        CompileMessage("Project is up to date", "");
        IsMaking(FALSE);
        return 0;
    }
    if (uState != notDebugging)
    {
        if (ExtendedMessageBox("Build", MB_YESNO, 
            "Target Build requires the debugger be stopped.\r\nStop the debugger now?") != IDYES)
        {
            browsing = FALSE;
            IsMaking(FALSE);
            return 0;
        }
        abortDebugThread();
    }
    TagLinesAdjust(0, TAGM_UPDATEDEBUG);
    stopBuild = FALSE;
	for (i=0; i < 2 && !stopBuild; i++)
	{
		l = projectList;
	    while (l && !stopBuild)
	    {
			int len = strlen(l->name);
			
			int lib ;
			if (len >= 4)
				len -= 4;
			lib = !stricmp(l->name + len, ".dll") || !stricmp(l->name + len, ".lib");
	        if (l->rebuild && (!selectedProject || l == selectedProject) 
				&& (i == 0 && lib || i == 1 && !lib))
	        {
	            FILELIST *m ;
	            int dont = PrePost(l, "Pre Build: ", l->prebuildlabel, l
	                ->prebuildsteps);
	            CalcRebuilds();
	            if (!dont && !stopBuild)
	            {
	                SendErrorMessage(ERR_BUILD_WINDOW, "Compiling...\r\n");
	                m = l->sourceFiles;
	                while (m && !stopBuild)
	                {
	                    if (m->rebuild)
	                    {
	                        dont |= buildFile(l, m);
	                        m->rebuild = FALSE;
	
	                    }
	                    m = m->next;
	                }
	                m = l->resourceFiles;
	                while (m && !stopBuild)
	                {
	                    if (m->rebuild)
	                    {
	                        dont |= buildFile(l, m);
	                        m->rebuild = FALSE;
	
	                    }
	                    m = m->next;
	                }
	                if (!dont && !stopBuild)
	                {
	                    if (l->buildType == BT_LIBRARY)
	                        dont |= libFile(l);
	                    else
	                    {
	                        dont |= linkFile(l);
	                    }
	                    if (!dont)
	                        dont = PrePost(l, "Post Build: ", l->postbuildlabel, l
	                            ->postbuildsteps);
	                }
	            }
	            if (!dont && !stopBuild && (l->buildFlags & BF_CHANGEDTARGET))
				{
	                l->buildFlags &= ~BF_CHANGEDTARGET;
					l->changed = TRUE;
					changedProject = TRUE;
				}
	            globalerr |= dont;
	        }
	        l = l->next;
	    }
	}
    if (stopBuild)
    {
        SendErrorMessage(ERR_BUILD_WINDOW, "Build Process Aborted\r\n");
    }
    else
    {
        ErrWarnCounts();
        if (!errcount && browseInfo)
        {
            FreeBrowseInfo();
            browseFile(projectList);
			FreeJumpSymbols();
			LoadJumpSymbols();
        }
    }
    CheckEditWindowChanged();
	if (!errcount)
	    MessageBeep(MB_ICONEXCLAMATION);
	else
		MessageBeep(MB_ICONASTERISK);
    if (browsing)
    {
        if (errcount)
            browsing = FALSE;
        else
            PostMessage(hwndFrame, WM_COMMAND, IDM_BROWSE, 0);
    }
    IsMaking(FALSE);
    return errcount;
}

//-------------------------------------------------------------------------

void CompilerThread(FILELIST *f)
{
    HWND win;
    IsMaking(TRUE);
    CreateTempFileName();
    errcount = warncount = 0;
    if (uState != notDebugging)
    {
        if (ExtendedMessageBox("Compiler", MB_YESNO, 
            "Compile requires the debugger be stopped.\r\nStop the debugger now?")
            != IDYES)
        {
            IsMaking(FALSE);
            return ;
        }
        abortDebugThread();
    }
    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);
    }
    dmgrHideWindow(DID_ERRORWND, FALSE);
	SelectErrorWindow(ERR_BUILD_WINDOW);
    OutputFile(f->parent, f, 0);
    buildFile(f->parent, f);
    ErrWarnCounts();
	if (!errcount)
	    MessageBeep(MB_ICONEXCLAMATION);
	else
		MessageBeep(MB_ICONASTERISK);
    IsMaking(FALSE);
}

//-------------------------------------------------------------------------

void Maker(int wParam)
{
    DWORD threadhand;
    if (wParam == IDM_STOPBUILD)
        stopBuild = TRUE;
    else
        CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MakerThread, 
            (LPVOID)wParam, 0, &threadhand));
}

//-------------------------------------------------------------------------

void Compiler(TREEDATA *data)
{
    DWORD threadhand;
    CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)CompilerThread, (void *)data->x.data, 0,
        &threadhand));
}

//-------------------------------------------------------------------------

int RebuildMessage(void)
{
    return ExtendedMessageBox("Debugger", MB_YESNO, 
        "Target needs to be rebuilt before debugging,\nDo you want to rebuild?") ==
        IDYES;
    #ifdef XXXXX
        static char *header = "The following files need to be rebuilt:\n\n";
        static char *trailer = "\n\n rebuild project before debugging?";
        int rv;
        char *buf,  *p;
        int size = 0, count = 0;
        PROJLIST *l = projectList;
        while (l)
        {
            FILELIST *m = l->sourceFiles;
            while (m)
            {
                DEPENDSLIST *n = m->depends;
                while (n)
                {
                    if (n->rebuild)
                    {
                        size += strlen(n->title);
                        count++;
                    }
                    n = n->next;
                }
                if (m->rebuild)
                {
                    size += strlen(m->title);
                    count++;
                }
                m = m->next;
            }
            l = l->next;
        }
        if (!count)
            size += count + 1+strlen(header) + strlen(trailer);
        buf = calloc(1,size);
        if (!buf)
            return ExtendedMessageBox("Debugger", MB_YESNO, 
                "Target needs to be rebuilt before debugging,\nDo you want to rebuild?") == IDYES;
        l = projectList;
        strcpy(buf, header);
        p = buf + strlen(buf);
        while (l)
        {
            FILELIST *m = l->sourceFiles;
            while (m)
            {
                DEPENDSLIST *n = m->depends;
                while (n)
                {
                    if (n->rebuild)
                    {
                        sprintf(p, "%s\n", n->title);
                        p += strlen(p);
                    }
                    n = n->next;
                }
                m = m->next;
            }
            l = l->next;
        }
        l = projectList;
        while (l)
        {
            FILELIST *m = l->sourceFiles;
            while (m)
            {
                if (m->rebuild)
                {
                    sprintf(p, "%s\n", m->title);
                    p += strlen(p);
                }
                m = m->next;
            }
            l = l->next;
        }
        strcat(p, trailer);
        rv = MessageBox(0, buf, "Build", MB_YESNO) == IDYES;
        free(buf);
        return rv;
    #endif 
}

//-------------------------------------------------------------------------

void dbgRebuildMainThread(int cmd)
{
    PROJLIST *plist;
    int i;
	cmd &= 0xffff;
    plist = ProjectFindSelectedEXE(0);
    if (!plist)
    {
        ExtendedMessageBox("Debugger", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
            "No Target Selected");
    }
    else
    {
        if (xstricmp(plist->name + strlen(plist->name) - 4, ".exe"))
            ExtendedMessageBox("Debugger", MB_SETFOREGROUND | MB_SYSTEMMODAL,
                "Selected target %s is not an EXE file", plist->title);
        else
        {
            int rebuild = FALSE;
            markProjects(0);
            if (CalcRebuilds() || AnyModified())
            {
                if (RebuildMessage())
                {
                    if (MakerThread(IDM_MAKE))
                        return ;
                }
            }
            else if (plist->buildFlags &BF_CHANGEDTARGET)
            {
                if (ExtendedMessageBox("Debugger", MB_YESNO, 
                    "Target needs to be rebuilt before debugging,\nDo you want to rebuild?") == IDYES)
                {
                    if (MakerThread(IDM_BUILDSELECTED))
                        return ;
                }
            }
            initiateDebug(plist, !TagAnyBreakpoints() || cmd == IDM_STEPIN || cmd == IDM_STEPOUT || cmd == IDM_STEPOVER);
            if (cmd != IDM_STARTSTOP)
            {
                i = SendMessage(hwndToolDebug, TB_GETSTATE, IDM_STARTSTOP, 0);
                SendMessage(hwndToolDebug, TB_SETSTATE, IDM_STARTSTOP, MAKELONG
                    (TBSTATE_CHECKED | i, 0));
            }
            return ;
        }
    }
    i = SendMessage(hwndToolDebug, TB_GETSTATE, IDM_STARTSTOP, 0);
    SendMessage(hwndToolDebug, TB_SETSTATE, IDM_STARTSTOP, MAKELONG
        (~TBSTATE_CHECKED &i, 0));
}

//-------------------------------------------------------------------------

void dbgRebuildMain(int cmd)
{
    DWORD threadhand;
    if (cmd == IDM_STOPBUILD)
        stopBuild = TRUE;
    else
        CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)
            dbgRebuildMainThread, (LPVOID)cmd, 0, &threadhand));
}
