/* 
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 <richedit.h>
#include <stdio.h>
#include <ctype.h>

#define PROJVERS 5
#define WSPVERS 7

#include "header.h"
#include "xml.h"

extern HWND hwndTbFind;
extern int memoryWordSize;
extern HANDLE children[MAX_CHILDREN];
extern int numberofdrawwindows;
extern HINSTANCE hInstance;
extern HWND hwndProject;
extern int changedProject;
extern char szProjectFilter[];
extern struct tagfile *tagFileList;
extern char szWorkspaceTitle[], szWorkspaceName[];
extern HWND hwndToolEdit, hwndToolDebug, hwndToolBuild;
extern LOGFONT EditFont;
extern HWND hwndClient, hwndStatus, hwndFrame;
extern PROJLIST *projectList;
extern int browseInfo;
extern char *findhist[MAX_COMBO_HISTORY];
extern char *fifdirhist[MAX_COMBO_HISTORY];
extern char *replacehist[MAX_COMBO_HISTORY];
extern char *watchhist[MAX_COMBO_HISTORY];
extern char *memhist[MAX_COMBO_HISTORY];
extern COLORREF keywordColor;
extern COLORREF numberColor;
extern COLORREF commentColor;
extern COLORREF stringColor;
extern COLORREF escapeColor;
extern COLORREF backgroundColor;
extern COLORREF textColor;
extern COLORREF highlightColor;
extern int custColors[16];
extern int numberofdrawwindows;
extern int editFlags, findflags, replaceflags;
extern DWINFO *newInfo;
extern HANDLE children[MAX_CHILDREN];
extern int tabs;
extern char szDrawClassName[];
extern char szUntitled[];
extern char hbpNames[4][256];
extern int hbpAddresses[4];
extern char hbpModes[4], hbpSizes[4], hbpEnables;
extern HWND hwndSourceTab;
extern int leftmargin, rightmargin, topmargin, bottommargin;
extern char printHeader[], printFooter[];
extern int completionEnabled;
extern int parenthesisCheck;
extern DWORD threadMain;

int restoredDocks = FALSE;
DWORD maximizeClient;

static char ipathbuf[2048];
//-------------------------------------------------------------------------

void abspath(char *name, char *path)
{
    char projname[256],  *p,  *nname = name;
	if (!path)
	{
		path = projname;
		GetCurrentDirectory(256, projname);
		strcat(projname,"\\hi");
	}
    if (!path[0])
        return ;
    if (name[0] == 0)
        return ;
    if (name[1] == ':')
        return ;
    strcpy(projname, path);
    p = strrchr(projname, '\\');
    if (!p)
        return ;
    p--;
    if (!strstr(name, "..\\"))
    {
        if (name[0] != '\\')
        {
            strcpy(p + 2, name);
            strcpy(nname, projname);
        }
        return ;
    }
    while (!strncmp(name, "..\\", 3))
    {
        while (p > projname &&  *p-- != '\\')
            ;
        name += 3;
    }
    *++p = '\\';
    p++;
    strcpy(p, name);
    strcpy(nname, projname);
}

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

char *relpath(char *name, char *path)
{
    static char projname[256], localname[256];
    char *p = localname,  *q = projname,  *r,  *s;
    if (!path[0])
        return name;
    if (toupper(name[0]) != toupper(path[0]))
        return name;

    strcpy(localname, name);
    strcpy(projname, path);
    r = strrchr(localname, '\\');
    if (r)
        *r++ = 0;
    // r has the point to the file name
    else
        r = localname;
    s = strrchr(projname, '\\');
    if (!s)
        return name;
    if (*s)
        *s = 0;

    while (*p &&  *q && toupper(*p) == toupper(*q))
	{
        p++, q++;
	}
    if (!(*p |  *q))
        return r;
    else if (*(p - 1) == '\\' && *(p - 2) == ':')
        return name;
    else
    {
        int count =  *q != 0;
		if (*q != '\\')
	        while (p > localname &&  *p != '\\')
    	        p--;
        while (*q && (q = strchr(q + 1, '\\')))
            count++;
        projname[0] = 0;
        while (count--)
            strcat(projname, "..\\");
        if (*p)
        {
            strcat(projname, p + 1);
            strcat(projname, "\\");
        }
        strcat(projname, r);
        return projname;
    }
}

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

void absincludepath(char *name, char *path)
{
    char *p = ipathbuf,  *dest1 = name,  *dest2 = name;
    strcpy(ipathbuf, name);
    name[0] = 0;
    do
    {
        char *q;
        if (*p == ';')
            p++;
        q = p;
        dest1 = dest2;
        p = strchr(p, ';');
        if (!p)
            p = ipathbuf + strlen(ipathbuf);
        while (q != p)*dest2++ =  *q++;
        *dest2 = 0;
        abspath(dest1, path);
        dest2 = dest1 + strlen(dest1);
        if (*p)
            *dest2++ = ';';
    }
    while (*p)
        ;
}

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

char *relincludepath(char *name, char *path)
{
    char *p = name,  *dest1 = ipathbuf,  *dest2 = ipathbuf;
    ipathbuf[0] = 0;
    do
    {
        char *q;
        if (*p == ';')
            p++;
        q = p;
        dest1 = dest2;
        p = strchr(p, ';');
        if (!p)
            p = name + strlen(name);
        while (q != p)*dest2++ =  *q++;
        *dest2 = 0;
        strcpy(dest1, relpath(dest1, path));
        dest2 = dest1 + strlen(dest1);
        if (*p)
            *dest2++ = ';';
    }
    while (*p)
        ;
    return ipathbuf;
}

PROJLIST *LoadErr(struct xmlNode *root, char *name, PROJLIST *list)
{
    xmlFree(root);
    projectList = list;
    ProjectFreeList();
    ExtendedMessageBox("Load Error", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
        "Target File %s is the wrong format", name);
    return 0;
} PROJLIST *NoMemory(struct xmlNode *root, char *list)
{
    xmlFree(root);
    projectList = list;
    ProjectFreeList();
    ExtendedMessageBox("Load Error", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
        "Out of memory");
    return 0;
} 

void NoMemoryWS(void)
{
    ExtendedMessageBox("Load Error", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
        "Out of memory");
}

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

int IsNode(struct xmlNode *node, char *name)
{
    return (!strcmp(node->elementType, name));
} int IsAttrib(struct xmlAttr *attr, char *name)
{
    return (!strcmp(attr->name, name));
} void addcr(char *buf)
{
    char buf2[2048],  *p = buf2;
    strcpy(buf2, buf);
    while (*p)
    {
        if (*p == '\n')
            *p++ = '\r';
        *buf++ =  *p++;
    }
    *buf = 0;


}

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

void RestorePlacement(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
    while (attribs)
    {
        if (IsAttrib(attribs, "VALUE"))
        {
            WINDOWPLACEMENT wp;
            wp.length = sizeof(WINDOWPLACEMENT);
            sscanf(attribs->value, "%d %d %d %d %d %d %d %d %d %d %d",  &wp.flags,
                &wp.showCmd,  &wp.ptMinPosition.x, &wp.ptMinPosition.y, 
                &wp.ptMaxPosition.x, &wp.ptMaxPosition.y, 
                &wp.rcNormalPosition.left, &wp.rcNormalPosition.top, 
                &wp.rcNormalPosition.right, &wp.rcNormalPosition.bottom, &maximizeClient);
            wp.flags = 0;
            SetWindowPlacement(hwndFrame, &wp);
			
        } 
		attribs = attribs->next;
    }
}

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

void RestoreDocks(struct xmlNode *node, int version)
{
    CCD_params d[20];
    int ids[20];
    int count = 0;
    struct xmlNode *dchildren = node->children;
    while (dchildren && count < 20)
    {
        if (IsNode(dchildren, "DOCK"))
        {
            struct xmlAttr *attribs = dchildren->attribs;
            while (attribs)
            {
                if (IsAttrib(attribs, "ID"))
                    ids[count] = atoi(attribs->value);
                else if (IsAttrib(attribs, "VALUE"))
                {
                    sscanf(attribs->value, 
                        "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d>\n",  
                        &d[count].flags, &d[count].flexparams,  
                        &d[count].rowindex, &d[count].colindex,  
                        &d[count].hidden, &d[count].hiddenwidth,  
                        &d[count].oldsize.left, &d[count].oldsize.top, 
                        &d[count].oldsize.right, &d[count].oldsize.bottom,  
                        &d[count].position.left, &d[count].position.top, 
                        &d[count].position.right, &d[count].position.bottom,  
                        &d[count].lastposition.left, &d[count].lastposition.top, 
                        &d[count].lastposition.right, &d[count].lastposition.bottom);						
                } attribs = attribs->next;
            }
            adjustforbadplacement(ids[count], &d[count]);
            count++;
        }
        dchildren = dchildren->next;
    }
	if (count)
	{
	    dmgrSetInfo(ids, &d[0], count);
		restoredDocks = TRUE;
	}
}

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

void RestoreHistory(struct xmlNode *node, int version)
{
    int count = 0;
    char buf[256];
    char **histitem = 0;
    struct xmlAttr *attribs = node->attribs;
    struct xmlNode *children = node->children;
    while (attribs)
    {
        if (IsAttrib(attribs, "TYPE"))
        {
            if (!strcmp(attribs->value, "FIND"))
                histitem = findhist;
            else if (!strcmp(attribs->value, "FIFDIR"))
                histitem = fifdirhist;
            else if (!strcmp(attribs->value, "REPLACE"))
                histitem = replacehist;
            else if (!strcmp(attribs->value, "WATCH"))
                histitem = watchhist;
            else if (!strcmp(attribs->value, "MEMORY"))
                histitem = memhist;
        } 
		attribs = attribs->next;
    }
    if (!histitem)
        return ;
    for (count = 0; count < MAX_COMBO_HISTORY; count++)
    if (histitem[count])
    {
        free(histitem[count]);
        histitem[count] = 0;
    }
    count = 0;
    while (children && count < MAX_COMBO_HISTORY)
    {
        if (IsNode(children, "HISTITEM"))
        {
            attribs = children->attribs;
            while (attribs && count < MAX_COMBO_HISTORY)
            {
                if (IsAttrib(attribs, "VALUE"))
                {
                    histitem[count++] = strdup(attribs->value);
                }
                attribs = attribs->next;
            }
        }
        children = children->next;
    }
    if (histitem == findhist)
        SendMessage((HWND)hwndTbFind, WM_SETHISTORY, 0, (LPARAM)findhist);
}

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

int RestoreFont(struct xmlNode *node, int version)
{
    int i, j = 0, n;
    LOGFONT lf;
    char *bf = node->textData;
    for (i = 0; i < sizeof(LOGFONT); i++)
    {
        sscanf(bf, "%d%n", &n, &j);
        *(((unsigned char*) &lf) + i) = n;
        bf += j;
    } 

    ApplyFontSettings(&lf);
}

int RestorePrinter(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
	struct xmlNode * children = node->children;
    while (attribs)
    {
        if (IsAttrib(attribs, "LEFT"))
            leftmargin = atoi(attribs->value);
        else if (IsAttrib(attribs, "RIGHT"))
            rightmargin = atoi(attribs->value);
        else if (IsAttrib(attribs, "TOP"))
            topmargin = atoi(attribs->value);
        else if (IsAttrib(attribs, "BOTTOM"))
            bottommargin = atoi(attribs->value);

        attribs = attribs->next;
	}
	while (children)
	{
		if (IsNode(children, "HEADER"))
		{
			int l = strlen(children->textData);
			if (l)
			{
				strcpy(printHeader, children->textData+ 1);
				if (l > 1)
				{
					printHeader[l-2] = 0;
				}
			}
		}
		else if (IsNode(children, "FOOTER"))
		{
			int l = strlen(children->textData);
			if (l)
			{
				strcpy(printFooter, children->textData+ 1);
				if (l > 1)
				{
					printFooter[l-2] = 0;
				}
			}
		}
		children = children->next;
	}
}
//-------------------------------------------------------------------------

void RestoreColors(struct xmlNode *node, int version)
{
    int i, j = 0;
    struct xmlAttr *attribs = node->attribs;
    char *bf = node->textData;
    while (attribs)
    {
        if (IsAttrib(attribs, "KEYWORD"))
            keywordColor = atoi(attribs->value);
        else if (IsAttrib(attribs, "NUMBER"))
            numberColor = atoi(attribs->value);
        else if (IsAttrib(attribs, "COMMENT"))
            commentColor = atoi(attribs->value);
        else if (IsAttrib(attribs, "STRING"))
            stringColor = atoi(attribs->value);
        else if (IsAttrib(attribs, "ESCAPE"))
            escapeColor = atoi(attribs->value);
        else if (IsAttrib(attribs, "BACKGROUND"))
            backgroundColor = atoi(attribs->value);
        else if (IsAttrib(attribs, "TEXT"))
            textColor = atoi(attribs->value);
        else if (IsAttrib(attribs, "HIGHLIGHT"))
            highlightColor = atoi(attribs->value);

        attribs = attribs->next;
    } 
	for (i = 0; i < 16; i++)
    {
        sscanf(bf, "%d%n", &custColors[i], &j);
        bf += j;
    }
}

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

void RestoreTabs(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
    while (attribs)
    {
        if (IsAttrib(attribs, "SPACING"))
            tabs = atoi(attribs->value);
        attribs = attribs->next;
    } 
}

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

void RestoreEditflags(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
    while (attribs)
    {
        if (IsAttrib(attribs, "FLAGS"))
            editFlags = atoi(attribs->value);
        attribs = attribs->next;
    } 
}
void RestoreMemoryWindowSettings(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
    while (attribs)
    {
        if (IsAttrib(attribs, "WORDSIZE"))
            memoryWordSize = atoi(attribs->value);
        attribs = attribs->next;
    } 
}
//-------------------------------------------------------------------------

void RestoreFindflags(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
    while (attribs)
    {
        if (IsAttrib(attribs, "FLAGS1"))
            findflags = atoi(attribs->value);
        if (IsAttrib(attribs, "FLAGS2"))
            replaceflags = atoi(attribs->value);
        attribs = attribs->next;
    } 
}

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

void RestoreWindows(struct xmlNode *node, int version)
{
    MDICREATESTRUCT mc;
    static DWINFO info;
	int old = maximizeClient;
    int i;
    struct xmlNode *child = node->children;
	HWND hwnd = NULL;
	ShowWindow(hwndSourceTab, SW_HIDE);
    while (child)
    {
        if (IsNode(child, "WINDOW"))
        {
            struct xmlAttr *attribs = child->attribs;
            memset(&info, 0, sizeof(info));
            memset(&mc, 0, sizeof(mc));
            while (attribs)
            {
                if (IsAttrib(attribs, "NAME"))
                {
                    strcpy(info.dwName, attribs->value);
                    abspath(info.dwName, szWorkspaceName);
                } 
                else if (IsAttrib(attribs, "TITLE"))
                    strcpy(info.dwTitle, attribs->value);
                else if (IsAttrib(attribs, "X"))
                    mc.x = atoi(attribs->value);
                else if (IsAttrib(attribs, "Y"))
                    mc.y = atoi(attribs->value);
                else if (IsAttrib(attribs, "WIDTH"))
                    mc.cx = atoi(attribs->value);
                else if (IsAttrib(attribs, "HEIGHT"))
                    mc.cy = atoi(attribs->value);
                else if (IsAttrib(attribs, "LINENO"))
                    info.dwLineNo = atoi(attribs->value);
                attribs = attribs->next;
            }
            newInfo = &info;
			hwnd = CreateMDIWindow(szDrawClassName, szUntitled,  WS_VISIBLE |
    			WS_CHILD | WS_OVERLAPPEDWINDOW | WS_SYSMENU | MDIS_ALLCHILDSTYLES |
        		WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
				mc.x,mc.y,mc.cx,mc.cy, hwndClient, hInstance, 0); 
//			PostMessage(hwndClient, WM_MDIACTIVATE, (WPARAM) hwnd, 0);
        }
        child = child->next;
    }
//	for (i=0; i < numberofdrawwindows; i++)
//		ShowWindow(children[i], SW_SHOW);
	ShowWindow(hwndSourceTab, SW_SHOW);
	if (hwnd)
	{
		maximizeClient = old;
		SendMessage(hwndClient, maximizeClient ? WM_MDIMAXIMIZE : WM_MDIRESTORE, (WPARAM)hwnd, 0);
	}
}

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

void RestoreChangeLn(struct xmlNode *node, int version)
{
    struct xmlNode *children = node->children;
    struct tagfile *l,  **ls = &tagFileList;
    struct xmlAttr *attribs;
    while (*ls)
        ls = &(*ls)->next;
    while (children)
    {
        if (IsNode(children, "FILE"))
        {
            struct xmlNode *fchildren = children->children;
            struct tagchangeln *c = 0,  **x = &c;
            *ls = calloc(sizeof(struct tagfile), 1);
            if (!ls)
            {
                NoMemoryWS();
                return ;
            } attribs = children->attribs;
            while (attribs)
            {
                if (IsAttrib(attribs, "NAME"))
                {
                    strcpy((*ls)->name, attribs->value);
                    abspath((*ls)->name, szWorkspaceName);
                }
                attribs = attribs->next;
            }
            l = tagFileList;
            while (l)
            {
                if (!strcmp(l->name, (*ls)->name))
                    break;
                l = l->next;
            }
            if (l !=  *ls)
            {
                free(*ls);
                *ls = 0;
            }
            else
                ls = &(*ls)->next;
            while (fchildren)
            {
                if (IsNode(fchildren, "LINE"))
                {
                    // assumes enumerated in order
                    *x = calloc(sizeof(struct tagchangeln), 1);
                    if (! *x)
                    {
                        NoMemoryWS();
                        return ;
                    } attribs = fchildren->attribs;
                    while (attribs)
                    {
                        if (IsAttrib(attribs, "NUM"))
                            (*x)->lineno = atoi(attribs->value);
                        else if (IsAttrib(attribs, "DELTA"))
                            (*x)->delta = atoi(attribs->value);
                        attribs = attribs->next;
                    }
                    x = &(*x)->next;
                }
                fchildren = fchildren->next;
            }
            l->changedLines = c;
        }
        children = children->next;
    }
}

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

void RestoreTags(struct xmlNode *node, int version)
{
    struct tagfile *l,  **ls = &tagFileList;
    struct tag *t,  **ts;
    struct xmlAttr *attribs = node->attribs;
    struct xmlNode *children = node->children;
    int tagid =  - 1;
    while (attribs)
    {
        if (IsAttrib(attribs, "ID"))
            tagid = atoi(attribs->value);
        attribs = attribs->next;
    } if (tagid ==  - 1 || tagid != TAG_BP && tagid != TAG_BOOKMARK)
        return ;
    while (*ls)
        ls = &(*ls)->next;
    while (children)
    {
        if (IsNode(children, "FILE"))
        {
            struct xmlNode *fchildren = children->children;
            *ls = calloc(sizeof(struct tagfile), 1);
            if (!ls)
            {
                NoMemoryWS();
                return ;
            } attribs = children->attribs;
            while (attribs)
            {
                if (IsAttrib(attribs, "NAME"))
                {
                    strcpy((*ls)->name, attribs->value);
                    abspath((*ls)->name, szWorkspaceName);
                }
                attribs = attribs->next;
            }
            l = tagFileList;
            while (l)
            {
                if (!strcmp(l->name, (*ls)->name))
                    break;
                l = l->next;
            }
            if (l !=  *ls)
            {
                free(*ls);
                *ls = 0;
            }
            else
                ls = &(*ls)->next;
            ts = &l->tagArray[tagid];
            while (fchildren)
            {
                if (IsNode(fchildren, "TAGITEM"))
                {
                    *ts = calloc(sizeof(struct tag), 1);
                    if (! *ts)
                    {
                        NoMemoryWS();
                        return ;
                    } 
					attribs = fchildren->attribs;
                    while (attribs)
                    {
                        if (IsAttrib(attribs, "LINENO"))
                            (*ts)->drawnLineno = (*ts)->editingLineno = (*ts)
                                ->debugLineno = atoi(attribs->value);
                        else if (IsAttrib(attribs, "CP"))
                            (*ts)->charpos = atoi(attribs->value);
                        else if (IsAttrib(attribs, "ENABLED"))
                            (*ts)->enabled = atoi(attribs->value);
                        attribs = attribs->next;
                    }
                    if (tagid == TAG_BOOKMARK)
                    {
                        (*ts)->extra = strdup(fchildren->textData);
                    }
                    ts = &(*ts)->next;
                }
                fchildren = fchildren->next;
            }
        }
        children = children->next;
    }
}

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

void RestoreBrowse(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
    while (attribs)
    {
        if (IsAttrib(attribs, "VALUE"))
			if (version >= 6) // resetting to the new default at this version
	            browseInfo = atoi(attribs->value);
        if (IsAttrib(attribs, "COMPLETION"))
            completionEnabled = atoi(attribs->value);
        if (IsAttrib(attribs, "PARENTHESIS"))
            parenthesisCheck = atoi(attribs->value);
        attribs = attribs->next;
    } 
    CalculateLayout( - 1, FALSE);
}

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

void RestoreWatch(struct xmlNode *node, int version)
{
    struct xmlAttr *attribs = node->attribs;
    int id = 0;
    while (attribs)
    {
        if (IsAttrib(attribs, "ID"))
        {
            // ID MUST BE FIRST!!!!!
            id = atoi(attribs->value) - 1;
            if (id < 0 || id > 3)
                return ;
        } 
        else if (IsAttrib(attribs, "ENABLE"))
        {
            if (atoi(attribs->value))
                hbpEnables |= (1 << id);
        }
        else if (IsAttrib(attribs, "NAME"))
        {
            strncpy(hbpNames[id], attribs->value, 255);
            hbpNames[id][255] = 0;
        }
        else if (IsAttrib(attribs, "MODE"))
        {
            hbpModes[id] = atoi(attribs->value);
        }
        else if (IsAttrib(attribs, "SIZE"))
        {
            hbpSizes[id] = atoi(attribs->value);
        }
        attribs = attribs->next;
    }
}

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

void RestoreToolBars(struct xmlNode *node, int version)
{
    int id = 0;
    HWND hwnd;
    char *horiz = 0,  *vert = 0;
    struct xmlAttr *attribs = node->attribs;
	if (version != WSPVERS)
		return;
    while (attribs)
    {
        if (IsAttrib(attribs, "ID"))
            id = atoi(attribs->value);
        else if (IsAttrib(attribs, "HORIZ"))
            horiz = attribs->value;
        else if (IsAttrib(attribs, "VERT"))
            vert = attribs->value;
        attribs = attribs->next;
    } 
	if (id && horiz && vert)
    {
        switch (id)
        {
            case DID_EDITTOOL:
                hwnd = hwndToolEdit;
                break;
            case DID_BUILDTOOL:
                hwnd = hwndToolBuild;
                break;
            case DID_DEBUGTOOL:
                hwnd = hwndToolDebug;
                break;
            default:
                return ;
        }
        SetToolBarData(hwnd, horiz, vert);
    }
}

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

struct projectData
{
	char *name; 
	int flags;
	int dbgview;
} ;
struct projectData *RestoreProjectNames(struct xmlNode *node, int version)
{
    struct xmlNode *children = node->children;
	static struct projectData data[1024];
    int i = 0;
    memset(data,0,sizeof(data));
    while (children)
    {
        if (IsNode(children, "FILE"))
        {
            struct xmlAttr * attribs = children->attribs ;
            while (attribs)
            {
                if (IsAttrib(attribs, "NAME"))
                {
                    data[i].name = attribs->value; // safe until workspace is unloaded
                }
                else if (IsAttrib(attribs, "FLAGS"))
				{
                    data[i].flags = strtol(attribs->value,0,16);
				}
                else if (IsAttrib(attribs, "DEBVIEW"))
				{
                   data[i].dbgview = strtol(attribs->value,0,16);
				}
                attribs = attribs->next ;
            }
			i++;
        }
        children = children->next ;
    }
    return data;
}

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

int RestoreWorkSpace(char *name, int toerr)
{
    int version;
    FILE *in;
    struct xmlNode *root;
    struct xmlNode *nodes,  *children;
    struct xmlAttr *attribs;
	struct projectData *projectNames = NULL;
    char buf[256],  *p; 
    in = fopen(name, "r");
    if (!in)
    {
        if (toerr)
            ExtendedMessageBox("Load Error", MB_SETFOREGROUND | MB_SYSTEMMODAL,
                "Workspace File Not Found");
        return 0;
    }
    root = xmlReadFile(in);
    fclose(in);
    if (!root || !IsNode(root, "CC386WORKSPACE"))
    {
        ExtendedMessageBox("Load Error", 0, "Workspace is invalid file format");
        return 0;
    }
    TagEraseAllEntries();
    CloseAll();
    hbpInit();
    nodes = root->children;
    while (nodes)
    {
        if (IsNode(nodes, "VERSION"))
        {
            struct xmlAttr *attribs = nodes->attribs;
            while (attribs)
            {
                if (IsAttrib(attribs, "ID"))
                    version = atoi(attribs->value);
                attribs = attribs->next;
            } 
        }
        else if (IsNode(nodes, "COLORS"))
            RestoreColors(nodes, version);
        else if (IsNode(nodes, "TABS"))
            RestoreTabs(nodes, version);
        else if (IsNode(nodes, "EDITOR"))
            RestoreEditflags(nodes, version);
        else if (IsNode(nodes, "MEMWND"))
            RestoreMemoryWindowSettings(nodes, version);
		else if (IsNode(nodes, "PRINTER"))
			RestorePrinter(nodes, version);
        else if (IsNode(nodes, "FIND"))
            RestoreFindflags(nodes, version);
        else if (IsNode(nodes, "HISTORY"))
            RestoreHistory(nodes, version);
        else if (IsNode(nodes, "FONT"))
            RestoreFont(nodes, version);
        else if (IsNode(nodes, "EDITWINDOWS"))
            RestoreWindows(nodes, version);
        else if (IsNode(nodes, "TAG"))
            RestoreTags(nodes, version);
        else if (IsNode(nodes, "PLACEMENT"))
            RestorePlacement(nodes, version);
        else if (IsNode(nodes, "DOCKS"))
            RestoreDocks(nodes, version);
        else if (IsNode(nodes, "TOOLBAR"))
            RestoreToolBars(nodes, version);
        else if (IsNode(nodes, "BROWSE"))
            RestoreBrowse(nodes, version);
        else if (IsNode(nodes, "WATCH"))
            RestoreWatch(nodes, version);
        else if (IsNode(nodes, "CHANGELN"))
            RestoreChangeLn(nodes, version);
        else if (IsNode(nodes, "TARGETS"))
            projectNames = RestoreProjectNames(nodes, version);
        nodes = nodes->next;
    }
    // needs to be before the XML free because the project names are taken in-place
    if (projectNames)
	{
		PROJLIST *l ;
		char *names[1024];
		int i;
		for (i=0; i <1024; i++)
			names[i] = projectNames[i].name ;
        projectList = ProjectLoadList(names);
		l = projectList;
		while (l)
		{
			l->treeOpenFlags = projectNames->flags ;
			l->dbgview = projectNames->dbgview;
			projectNames++;
			l = l->next;
		}		
	}
    xmlFree(root);
	SendMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
	return 1;
}
FILELIST *RestoreFileData(struct xmlNode *root, PROJLIST *plist, PROJLIST *pl, 
        struct xmlNode *children)
{
    FILELIST *list = 0, **l = &list;
    children = children->children ; // down one level to the file list
    while (children) {
        if (IsNode(children, "FILE")) {
            DEPENDSLIST *dlist = 0,  **dl = &dlist;
            struct xmlNode *fchildren = children->children;
            struct xmlAttr *attribs;
            *l = calloc(sizeof(FILELIST), 1);
            if (! *l)
                return NoMemory(root, plist);
            (*l)->parent = pl;
            attribs = children->attribs;
            while (attribs)
            {
                if (IsAttrib(attribs, "NAME"))
                {
                    strcpy((*l)->name, attribs->value);
                    abspath((*l)->name, pl->projectName);
                } 
                else if (IsAttrib(attribs, "TITLE"))
                {
                    strcpy((*l)->title, attribs->value);
                }
                attribs = attribs->next;
            }
            while (fchildren)
            {
                if (IsNode(fchildren, "DEPENDENCY"))
                {
                    *dl = calloc(sizeof(DEPENDSLIST), 1);
                    if (! *dl)
                        return NoMemory(root, plist);
                    (*dl)->parent = pl;
        
                    attribs = fchildren->attribs;
                    while (attribs)
                    {
                        if (IsAttrib(attribs, "NAME"))
                        {
                            strcpy((*dl)->name, attribs->value);
                            abspath((*dl)->name, pl->projectName);
                        }
                        else if (IsAttrib(attribs, "TITLE"))
                        {
                            strcpy((*dl)->title, attribs->value);
                        }
                        attribs = attribs->next;
                    }
                }
                dl = &(*dl)->next;
                fchildren = fchildren->next;
            }
            (*l)->depends = dlist;
            l = &(*l)->next;
        }
        children = children->next ;
    }
    return list ;
}

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

PROJLIST *ProjectLoadList(char *name[])
{
    PROJLIST *plist = 0,  **pl = &plist;
    int i=0;
    char buf[2049];
    int temp, projectVersion;
    struct xmlNode *root;
    struct xmlNode *targets,  *children;
    struct xmlAttr *attribs;
    while(name[i]) 
    {
        char projname[256];
        FILE *in;
        strcpy(projname, name[i++]);
        abspath(projname, szWorkspaceName);
        in = fopen(projname, "r");
        if (!in)
        {
            ExtendedMessageBox("Load Error", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
                "Project File %s Not Found",projname);
            return 0;
        }
        root = xmlReadFile(in);
        fclose(in);
        if (!root || !IsNode(root, "CC386TARGET"))
        {
            return LoadErr(root, projname, plist);
        }
        targets = root->children;
        while (targets)
        {
            if (IsNode(targets, "VERSION"))
            {
                attribs = targets->attribs;
                while (attribs)
                {
                    if (IsAttrib(attribs, "ID"))
                        projectVersion = atoi(attribs->value);
                    attribs = attribs->next;
                }
            }
            else if (IsNode(targets, "TARGET"))
            {
                FILELIST *flist = 0, *rlist = 0, *olist = 0;
                *pl = calloc(sizeof(*plist), 1);
                if (! *pl)
                    return NoMemory(root, plist);
                strcpy((*pl)->projectName, projname);
                attribs = targets->attribs;
                while (attribs)
                {
                    if (IsAttrib(attribs, "NAME"))
                    {
                        strcpy((*pl)->name, attribs->value);
                        abspath((*pl)->name, (*pl)->projectName);
                    }
                    else if (IsAttrib(attribs, "TITLE"))
                    {
                        strcpy((*pl)->title, attribs->value);
                    }
                    attribs = attribs->next;
                }
                children = targets->children;
                while (children)
                {
                    if (IsNode(children, "BUILD"))
                    {
                        attribs = children->attribs;
                        while (attribs)
                        {
                            if (IsAttrib(attribs, "TYPE"))
                                (*pl)->buildType = atoi(attribs->value);
                            else if (IsAttrib(attribs, "FLAGS"))
                                (*pl)->buildFlags = atoi(attribs->value);
                            else if (IsAttrib(attribs, "LIBTYPE"))
                                (*pl)->libType = atoi(attribs->value);
                            attribs = attribs->next;
                        }
                    }
                    else if (IsNode(children, "PATHS"))
                    {
                        attribs = children->attribs;
                        while (attribs)
                        {
                            if (IsAttrib(attribs, "INCLUDE"))
                            {
                                strcpy((*pl)->includePath, attribs->value);
                                absincludepath((*pl)->includePath, (*pl)->projectName);
                            }
                            else if (IsAttrib(attribs, "OUTPUT"))
                            {
                                strcpy((*pl)->outputPath, attribs->value);
                                abspath((*pl)->outputPath, (*pl)->projectName);
                            }
                            attribs = attribs->next;
                        }
                    }
                    else if (IsNode(children, "PREBUILD"))
                    {
                        attribs = children->attribs;
                        while (attribs)
                        {
                            if (IsAttrib(attribs, "LABEL"))
                            {
                                strcpy((*pl)->prebuildlabel, attribs->value);
                            }
                            attribs = attribs->next;
                        }
                        if (children->textData)
                        {
                            if (strlen(children->textData) > 1024)
                                return NoMemory(root, plist);
                            strcpy(buf, children->textData);
                            addcr(buf);
                            if (strlen(buf) > 1023)
                                return NoMemory(root, plist);
                            strcpy((*pl)->prebuildsteps, buf);
                        }
                    }
                    else if (IsNode(children, "POSTBUILD"))
                    {
                        attribs = children->attribs;
                        while (attribs)
                        {
                            if (IsAttrib(attribs, "LABEL"))
                            {
                                strcpy((*pl)->postbuildlabel, attribs->value);
                            }
                            attribs = attribs->next;
                        }
                        if (children->textData)
                        {
                            if (strlen(children->textData) > 1024)
                                return NoMemory(root, plist);
                            strcpy(buf, children->textData);
                            addcr(buf);
                            if (strlen(buf) > 1023)
                                return NoMemory(root, plist);
                            strcpy((*pl)->postbuildsteps, buf);
                        }
                    }
                    else if (IsNode(children, "OPTS"))
                    {
                        struct xmlNode *ochildren = children->children;
                        while (ochildren)
                        {
                            if (IsNode(ochildren, "COMPILER"))
                                strcpy((*pl)->compileopts, ochildren->textData);
                            if (IsNode(ochildren, "ASSEMBLER"))
                                strcpy((*pl)->assembleopts, ochildren->textData);
                            if (IsNode(ochildren, "LINKER"))
                                strcpy((*pl)->linkopts, ochildren->textData);
                            if (IsNode(ochildren, "LIBRARIAN"))
                                strcpy((*pl)->libopts, ochildren->textData);
                            ochildren = ochildren->next;
                        } 
                    }
                    else if (IsNode(children, "CMDLINE"))
                    {
                        int len;
                        strcpy((*pl)->cmdline, children->textData);
                    }
                    else if (IsNode(children, "DEFINE"))
                    {
                        DEFINES *d = calloc(sizeof(DEFINES), 1),  **dl = &(*pl)
                            ->defines;
                        if (!d)
                            return NoMemory(root, plist);
                        attribs = children->attribs;
                        while (attribs)
                        {
                            if (IsAttrib(attribs, "NAME"))
                                strcpy(d->name, attribs->value);
                            else if (IsAttrib(attribs, "VALUE"))
                                strcpy(d->value, attribs->value);
                            attribs = attribs->next;
                        }
                        while (*dl)
                            dl = &(*dl)->next;
                        *dl = d;
                    }
                    else if (IsNode(children, "DEFINEFLAGS"))
                    {
                        attribs = children->attribs;
                        while (attribs)
                        {
                            if (IsAttrib(attribs, "VALUE"))
                                (*pl)->defineFlags = atoi(attribs->value);
                            attribs = attribs->next;
                        }
                    }
                    else if (IsNode(children, "SOURCES"))
                    {
                        flist = RestoreFileData(root, plist, *pl, children);
                    }
                    else if (IsNode(children, "RESOURCES"))
                    {
                        rlist = RestoreFileData(root, plist, *pl, children);
                    }
                    else if (IsNode(children, "OTHER"))
                    {
                        olist = RestoreFileData(root, plist, *pl, children);
                    }
                    children = children->next;
                }
                (*pl)->sourceFiles = flist;
                (*pl)->otherFiles = olist;
                (*pl)->resourceFiles = rlist;
                pl = &(*pl)->next;
            }
            targets = targets->next;
        }
        xmlFree(root);
    }
    return plist;
}

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

char *nocr(char *s)
{
    static char buf[1024];
    char *p = buf;
    while (*s)
    {
        if (*s != '\r')
            *p++ =  *s;
        s++;
    }
    *p = 0;
    return buf;
}

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

void SaveSettings(FILE *out)
{
    int i;
    fprintf(out, "\t<COLORS KEYWORD=\"%d\" NUMBER=\"%d\" COMMENT=\"%d\"\n"
        "\t\t\tSTRING=\"%d\" ESCAPE=\"%d\" BACKGROUND=\"%d\"\n"
        "\t\t\tTEXT=\"%d\" HIGHLIGHT=\"%d\">\n\t\t", keywordColor, numberColor, commentColor,
        stringColor, escapeColor, backgroundColor, textColor, highlightColor);
    for (i = 0; i < 16; i++)
    {
        fprintf(out, "%d ", custColors[i]);
        if (i == 7)
            fprintf(out, "\n\t\t");
    }
    fprintf(out, "\n\t</COLORS>\n");
    fprintf(out, "\t<TABS SPACING=\"%d\"/>\n", tabs);
    fprintf(out, "\t<EDITOR FLAGS=\"%d\"/>\n", editFlags);
    fprintf(out, "\t<MEMWND WORDSIZE=\"%d\"/>\n", memoryWordSize);
    fprintf(out, "\t<FIND FLAGS1=\"%d\" FLAGS2=\"%d\"/>\n", findflags, replaceflags);
}

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

void onehistsave(FILE *out, char **hist, char *name)
{
    int i;
    fprintf(out, "\t<HISTORY TYPE=\"%s\">\n", name);
    for (i = 0; i < MAX_COMBO_HISTORY; i++)
        if (hist[i])
            fprintf(out, "\t\t<HISTITEM VALUE=\"%s\"/>\n", xmlConvertString(hist[i],TRUE));
    fprintf(out, "\t</HISTORY>\n");
}

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

int SaveHistory(FILE *out)
{
    onehistsave(out, findhist, "FIND");
    onehistsave(out, fifdirhist, "FIFDIR");
    onehistsave(out, replacehist, "REPLACE");
    onehistsave(out, watchhist, "WATCH");
    onehistsave(out, memhist, "MEMORY");
}

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

void SaveChangeLn(FILE *out)
{
    struct tagfile *list = tagFileList;
    fprintf(out, "\t<CHANGELN>\n");
    while (list)
    {
        if (list->changedLines)
        {
            struct tagchangeln *data = list->changedLines;
            fprintf(out, "\t\t<FILE NAME=\"%s\">\n", relpath(list->name, szWorkspaceName));
            while (data)
            {
                fprintf(out, "\t\t\t<LINE NUM=\"%d\" DELTA=\"%d\"\/>\n", data
                    ->lineno, data->delta);
                data = data->next;
            } fprintf(out, "\t\t</FILE>\n");
        }
        list = list->next;
    }
    fprintf(out, "\t</CHANGELN>\n");
}

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

void saveonetag(FILE *out, int tag)
{
    struct tagfile *list = tagFileList;
    fprintf(out, "\t<TAG ID=\"%d\">\n", tag);
    while (list)
    {
        if (list->tagArray[tag])
        {
            struct tag *data = list->tagArray[tag];
            fprintf(out, "\t\t<FILE NAME=\"%s\">\n", relpath(list->name, szWorkspaceName));
            while (data)
            {
                fprintf(out, 
                    "\t\t\t<TAGITEM LINENO=\"%d\" CP=\"%d\" ENABLED=\"%d\"",
                    data->drawnLineno, data->charpos, data->enabled);

                if (tag == TAG_BOOKMARK)
                    fprintf(out, ">\n%s\n\t\t\t</TAGITEM>\n", xmlConvertString
                        (data->extra, FALSE));
                else
                    fprintf(out, "/>\n");
                data = data->next;
            } fprintf(out, "\t\t</FILE>\n");
        }
        list = list->next;
    }
    fprintf(out, "\t</TAG>\n");
}

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

void SaveTags(FILE *out)
{
    saveonetag(out, TAG_BP);
    saveonetag(out, TAG_BOOKMARK);
}

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

void SaveFont(FILE *out)
{
    int i, j;
    fprintf(out, "\t<FONT>\n\t\t");
    for (i = 0; i < sizeof(LOGFONT); i += 16)
    {
        int k = sizeof(LOGFONT) - i;
        if (k > 16)
            k = 16;
        for (j = 0; j < k; j++)
            fprintf(out, "%d ", *(((unsigned char*) &EditFont) + i + j));
        if (k == 16)
            fprintf(out, "\n\t\t");
    }
    fprintf(out, "\n\t</FONT>\n");
}

void SavePrinter(FILE *out)
{
	fprintf(out,"\t<PRINTER LEFT=\"%d\" RIGHT=\"%d\" TOP=\"%d\" BOTTOM=\"%d\">\n", 
			leftmargin, rightmargin, topmargin, bottommargin);
	fprintf(out,"\t\t<HEADER>\n\t\t\t\"%s\"\n\t\t</HEADER>\n",
                xmlConvertString(printHeader, FALSE));
	fprintf(out,"\t\t<FOOTER>\n\t\t\t\"%s\"\n\t\t</FOOTER>\n",
                xmlConvertString(printFooter, FALSE));
	fprintf(out,"\t</PRINTER>\n");
}
//-------------------------------------------------------------------------

void SaveDocks(FILE *out)
{
    int i;
    CCW_params p[20];
    CCD_params d[20];
    int len;
    len = dmgrGetInfo(&p[0], &d[0]);
    fprintf(out, "\t<DOCKS>\n");
    for (i = 0; i < len; i++)
    {
        fprintf(out, 
            "\t\t<DOCK ID=\"%d\" VALUE=\"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\"/>\n", 
                p[i].id, 
                d[i].flags, d[i].flexparams, 
                d[i].rowindex, d[i].colindex, 
                d[i].hidden, d[i].hiddenwidth, 
                d[i].oldsize.left, d[i].oldsize.top, 
                d[i].oldsize.right, d[i].oldsize.bottom, 
                d[i].position.left, d[i].position.top, 
                d[i].position.right, d[i].position.bottom, 
                d[i].lastposition.left, d[i].lastposition.top, 
                d[i].lastposition.right, d[i].lastposition.bottom);
    }
    fprintf(out, "\t</DOCKS>\n");
}

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

void SaveWindows(FILE *out)
{
    int i;
    fprintf(out, "\t<EDITWINDOWS>\n");
    for (i = 0; i < numberofdrawwindows; i++)
    {
        POINT p;
        int startpos;
        WINDOWPLACEMENT placement;
        DWINFO *info = (DWINFO*)GetWindowLong(children[i], 0);
        charinfo a;
        SendMessage(GetDlgItem(children[i], ID_EDITCHILD), EM_EXGETSEL, 0, 
            (WPARAM) &a);
        startpos = SendMessage(GetDlgItem(children[i], ID_EDITCHILD),
            EM_EXLINEFROMCHAR, 0, a.min);
        placement.length = sizeof(placement);
        GetWindowPlacement(children[i], &placement);
        p.x = placement.rcNormalPosition.left;
        p.y = placement.rcNormalPosition.top;
        //      ScreenToClient(hwndClient,&p) ;
        fprintf(out, 
            "\t\t<WINDOW NAME=\"%s\" TITLE=\"%s\" X=\"%d\" Y=\"%d\" WIDTH=\"%d\" HEIGHT=\"%d\" LINENO=\"%d\"/>\n", relpath(info->dwName, szWorkspaceName), info->dwTitle, p.x, p.y, placement.rcNormalPosition.right - placement.rcNormalPosition.left, placement.rcNormalPosition.bottom - placement.rcNormalPosition.top, startpos + 1);
    }
    fprintf(out, "\t</EDITWINDOWS>\n");
}

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

void SaveToolBarA(FILE *out, HWND hwnd)
{
    char horiz[512], vert[512];
    int id = GetToolBarData(hwnd, horiz, vert);
    fprintf(out, "\t<TOOLBAR ID=\"%d\" HORIZ=\"%s\" VERT=\"%s\"/>\n", id, horiz,
        vert);
}

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

void SaveToolBars(FILE *out)
{
    WINDOWPLACEMENT wp;
	wp.length = sizeof(wp);
    GetWindowPlacement(hwndFrame, &wp);
    fprintf(out, "\t<PLACEMENT VALUE=\"%d %d %d %d %d %d %d %d %d %d %d\"/>\n",
        wp.flags, wp.showCmd, wp.ptMinPosition.x, wp.ptMinPosition.y,
        wp.ptMaxPosition.x, wp.ptMaxPosition.y, wp.rcNormalPosition.left,
        wp.rcNormalPosition.top, wp.rcNormalPosition.right,
        wp.rcNormalPosition.bottom, maximizeClient);
    SaveToolBarA(out, hwndToolEdit);
    SaveToolBarA(out, hwndToolBuild);
    SaveToolBarA(out, hwndToolDebug);
}

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

void SaveWatchpoints(FILE *out)
{
    int i;
    for (i = 0; i < 4; i++)
    {
        fprintf(out, 
            "\t<WATCH ID=\"%d\" ENABLE=\"%d\" NAME=\"%s\" MODE=\"%d\" SIZE=\"%d\"/>\n", i + 1, !!(hbpEnables &(1 << i)), xmlConvertString(hbpNames[i], TRUE), hbpModes[i], hbpSizes[i]);
    }
}

void SaveProjectNames(FILE *out)
{
    PROJLIST *l = projectList ;
    fprintf(out,"\t<TARGETS>\n");
    while (l)
    {
        fprintf(out,
            "\t\t<FILE NAME=\"%s\" FLAGS=\"%x\" DEBVIEW=\"%x\"/>\n", relpath(l->projectName, szWorkspaceName), l->treeOpenFlags, l->dbgview);
        l = l->next ;
    }
    fprintf(out,"\t</TARGETS>\n");
}
//-------------------------------------------------------------------------

void SaveWorkspace(char *name)
{
    FILE *out;
    char buf[256],  *p;
	ProjectSaveList();
    
	if (editFlags & BACKUP_PROJECTS)
		backup(name);	
	out = fopen(name, "w");
    if (!out)
    {
        ExtendedMessageBox("Save Error", 0, "Could not save workspace");
        return ;
    }
    fprintf(out, "<CC386WORKSPACE>\n");
    fprintf(out, "\t<VERSION ID=\"%d\"/>\n", WSPVERS);
    SaveSettings(out);
    SaveFont(out);
	SavePrinter(out);
    fprintf(out, "\t<BROWSE VALUE=\"%d\" COMPLETION=\"%d\" PARENTHESIS=\"%d\"/>\n", 
			browseInfo, completionEnabled, parenthesisCheck);
    SaveWatchpoints(out);
    SaveToolBars(out);
    SaveDocks(out);
    SaveWindows(out);
    SaveHistory(out);
    SaveTags(out);
    SaveChangeLn(out);
    SaveProjectNames(out);
    fprintf(out, "</CC386WORKSPACE>\n");
    fclose(out);
}

//-------------------------------------------------------------------------
void ProjectSaveList(void)
{
    PROJLIST *list = projectList;
    if (!projectList)
        return ;
    if (!changedProject)
        return ;
    changedProject = FALSE;
    while (list)
    {
        FILELIST *list1 ;
        DEFINES *d = list->defines;
        char buf[256];
        FILE *out ;
        if (list->changed)
        {
			if (editFlags & BACKUP_PROJECTS)
				backup(list->projectName);	
            out = fopen(list->projectName, "w");
            if (!out)
            {
                ExtendedMessageBox("Save Error", 0, "Could not save project %s", list->name);
                list = list->next;
                continue;
            }
            fprintf(out, "<CC386TARGET>\n\t<VERSION ID=\"%d\"/>\n", PROJVERS);
            buf[0] = 0;
            strcpy(buf, relpath(list->outputPath, list->projectName));
            strcpy(buf, xmlConvertString(buf, TRUE));
            fprintf(out, "\t<TARGET NAME=\"%s\" TITLE=\"%s\">\n",
                relpath(list->name, list->projectName),
				list->title);
            fprintf(out, "\t\t<BUILD TYPE=\"%d\" FLAGS=\"%d\" LIBTYPE=\"%d\"/>\n",
                list->buildType, list->buildFlags, list->libType);
            fprintf(out, "\t\t<DEFINEFLAGS VALUE=\"%d\"/>\n", list->defineFlags);
            fprintf(out, "\t\t<PATHS INCLUDE=\"%s\" OUTPUT=\"%s\"/>\n",
                xmlConvertString(relincludepath(list->includePath, list->projectName), TRUE), buf);
            strcpy(buf, xmlConvertString(list->prebuildlabel, TRUE));
            fprintf(out, "\t\t<PREBUILD LABEL=\"%s\">\n\t\t\t%s\n\t\t</PREBUILD>\n",
                buf, xmlConvertString(nocr(list->prebuildsteps), FALSE));
            strcpy(buf, xmlConvertString(list->postbuildlabel, TRUE));
            fprintf(out, 
                "\t\t<POSTBUILD LABEL=\"%s\">\n\t\t\t%s\n\t\t</POSTBUILD>\n", buf,
                xmlConvertString(nocr(list->postbuildsteps), FALSE));
            fprintf(out, "\t\t<OPTS>\n");
            fprintf(out, "\t\t\t<COMPILER>\n\t\t\t\t%s\n\t\t\t</COMPILER>\n",
                xmlConvertString(list->compileopts, FALSE));
            fprintf(out, "\t\t\t<ASSEMBLER>\n\t\t\t\t%s\n\t\t\t</ASSEMBLER>\n",
                xmlConvertString(list->assembleopts, FALSE));
            fprintf(out, "\t\t\t<LINKER>\n\t\t\t\t%s\n\t\t\t</LINKER>\n",
                xmlConvertString(list->linkopts, FALSE));
            fprintf(out, "\t\t\t<LIBRARIAN>\n\t\t\t\t%s\n\t\t\t</LIBRARIAN>\n",
                xmlConvertString(list->libopts, FALSE));
            fprintf(out, "\t\t</OPTS>\n");
            fprintf(out, "\t\t<CMDLINE>\n\t\t\t%s\n\t\t</CMDLINE>\n",
                xmlConvertString(list->cmdline, FALSE));
            while (d)
            {
                strcpy(buf, xmlConvertString(d->name, TRUE));
                fprintf(out, "\t\t<DEFINE NAME=\"%s\" VALUE=\"%s\"/>\n", buf,
                    xmlConvertString(d->value, TRUE));
                d = d->next;
            }
            list1 = list->sourceFiles ;
            fprintf(out,"\t\t<SOURCES>\n");
            while (list1)
            {
    
                fprintf(out, "\t\t\t<FILE NAME=\"%s\" TITLE=\"%s\"", relpath(list1
                    ->name, list->projectName), list1->title);
                if (list1->depends)
                {
                    DEPENDSLIST *d = list1->depends;
                    fprintf(out, ">\n");
                    while (d)
                    {
                        fprintf(out, 
                            "\t\t\t\t<DEPENDENCY NAME=\"%s\" TITLE=\"%s\"/>\n",
                            relpath(d->name, list->projectName), d->title);
                        d = d->next;
                    }
                    fprintf(out, "\t\t\t</FILE>\n");
                }
                else
                    fprintf(out, "/>\n");
                list1 = list1->next;
            }
            fprintf(out,"\t\t</SOURCES>\n");
            fprintf(out,"\t\t<RESOURCES>\n");
            list1 = list->resourceFiles;
            while (list1)
            {
    
                fprintf(out, "\t\t\t<FILE NAME=\"%s\" TITLE=\"%s\"", relpath(list1
                    ->name, list->projectName), list1->title);
                if (list1->depends)
                {
                    DEPENDSLIST *d = list1->depends;
                    fprintf(out, ">\n");
                    while (d)
                    {
                        fprintf(out, 
                            "\t\t\t\t<DEPENDENCY NAME=\"%s\" TITLE=\"%s\"/>\n",
                            relpath(d->name, list->projectName), d->title);
                        d = d->next;
                    }
                    fprintf(out, "\t\t\t</FILE>\n");
                }
                else
                    fprintf(out, "/>\n");
                list1 = list1->next;
            }
            fprintf(out,"\t\t</RESOURCES>\n");
            fprintf(out,"\t\t<OTHER>\n");
            list1 = list->otherFiles;
            while (list1)
            {
    
                fprintf(out, "\t\t\t<FILE NAME=\"%s\" TITLE=\"%s\"", relpath(list1
                    ->name, list->projectName), list1->title);
                if (list1->depends)
                {
                    DEPENDSLIST *d = list1->depends;
                    fprintf(out, ">\n");
                    while (d)
                    {
                        fprintf(out, 
                            "\t\t\t\t<DEPENDENCY NAME=\"%s\" TITLE=\"%s\"/>\n",
                            relpath(d->name, list->projectName), d->title);
                        d = d->next;
                    }
                    fprintf(out, "\t\t\t</FILE>\n");
                }
                else
                    fprintf(out, "/>\n");
                list1 = list1->next;
            }
            fprintf(out,"\t\t</OTHER>\n");
            fprintf(out, "\t</TARGET>\n");
            fprintf(out, "</CC386TARGET>\n");
            fclose(out);
            list->changed = FALSE ;
        }
        list = list->next;
    }
}
