buildtool.cpp revision be7b0d5f126473157a9fe026e7a9fd54ee4b27c5
/**
* Simple build automation tool.
*
* Authors:
* Bob Jamison
*
* Copyright (C) 2006 Bob Jamison
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
#include <dirent.h>
#include <string>
#include <map>
#include <set>
#include <vector>
#ifdef __WIN32__
#include <windows.h>
#endif
namespace buildtool
{
//########################################################################
//########################################################################
//## X M L
//########################################################################
//########################################################################
// Note: This mini-dom library comes from Pedro, another little project
// of mine.
typedef unsigned int XMLCh;
class Namespace
{
public:
{}
{
}
{
}
{
return *this;
}
virtual ~Namespace()
{}
{ return prefix; }
virtual String getNamespaceURI()
{ return namespaceURI; }
protected:
{
}
};
class Attribute
{
public:
{}
{
}
{
}
{
return *this;
}
virtual ~Attribute()
{}
{ return name; }
{ return value; }
protected:
{
}
};
class Element
{
friend class Parser;
public:
Element()
{
}
{
}
{
}
{
}
{
return *this;
}
virtual ~Element()
{
delete children[i];
}
{ return name; }
{ return value; }
{ return parent; }
{ return children; }
{ return attributes; }
/**
* Prettyprint an XML tree to an output stream. Elements are indented
* according to element hierarchy.
* @param f a stream to receive the output
* @param elem the element to output
*/
void writeIndented(FILE *f);
/**
* Prettyprint an XML tree to standard output. This is the equivalent of
* writeIndented(stdout).
* @param elem the element to output
*/
void print();
protected:
{
}
};
class Parser
{
public:
/**
* Constructor
*/
Parser()
{ init(); }
virtual ~Parser()
{}
/**
* Parse XML in a char buffer.
* @param buf a character buffer to parse
* @param pos position to start parsing
* @param len number of chars, from pos, to parse.
* @return a pointer to the root of the XML document;
*/
/**
* Parse XML in a char buffer.
* @param buf a character buffer to parse
* @param pos position to start parsing
* @param len number of chars, from pos, to parse.
* @return a pointer to the root of the XML document;
*/
/**
* Parse a named XML file. The file is loaded like a data file;
* the original format is not preserved.
* @param fileName the name of the file to read
* @return a pointer to the root of the XML document;
*/
/**
* Utility method to preprocess a string for XML
* output, escaping its entities.
* @param str the string to encode
*/
/**
* Removes whitespace from beginning and end of a string
*/
private:
void init()
{
keepGoing = true;
currentNode = NULL;
parselen = 0;
currentPosition = 0;
}
int skipwhite(long p);
int parseVersion(int p0);
int parseDoctype(int p0);
bool keepGoing;
long parselen;
long currentPosition;
int colNr;
};
//########################################################################
//# E L E M E N T
//########################################################################
{
{
}
return elem;
}
{
{
}
}
{
return res;
}
{
for (unsigned int i=0 ; i<attributes.size() ; i++)
return attributes[i].getValue();
return "";
}
{
return "";
return res;
}
{
return "";
return res;
}
{
if (!child)
return;
}
{
}
{
}
{
int i;
if (!f)
return;
//Opening tag, and attributes
for (i=0;i<indent;i++)
fputc(' ',f);
for (unsigned int i=0 ; i<attributes.size() ; i++)
{
fprintf(f," %s=\"%s\"",
}
for (unsigned int i=0 ; i<namespaces.size() ; i++)
{
fprintf(f," xmlns:%s=\"%s\"",
}
fprintf(f,">\n");
//Between the tags
{
for (int i=0;i<indent;i++)
fputc(' ', f);
}
//Closing tag
for (int i=0; i<indent; i++)
fputc(' ',f);
}
{
writeIndentedRecursive(f, 0);
}
{
}
//########################################################################
//# P A R S E R
//########################################################################
typedef struct
{
char *escaped;
char value;
} EntityEntry;
static EntityEntry entities[] =
{
{ "&" , '&' },
{ "<" , '<' },
{ ">" , '>' },
{ "'", '\'' },
{ """, '"' },
{ NULL , '\0' }
};
/**
* Removes whitespace from beginning and end of a string
*/
{
if (s.size() < 1)
return s;
//Find first non-ws char
unsigned int begin = 0;
{
break;
}
//Find first non-ws char, going in reverse
{
break;
}
//trace("begin:%d end:%d", begin, end);
return res;
}
{
long line = 1;
long col = 1;
for (long i=0 ; i<pos ; i++)
{
{
col = 0;
line ++;
}
else
col++;
}
}
{
long lineNr;
long colNr;
}
{
return -1;
//printf("ch:%c\n", ch);
return ch;
}
{
{
if (ch == '&')
else if (ch == '<')
else if (ch == '>')
else if (ch == '\'')
else if (ch == '"')
else
}
return ret;
}
{
int p = p0;
while (*text)
{
return p0;
p++; text++;
}
return p;
}
{
while (p<parselen)
{
if (p2 > p)
{
p = p2;
while (p<parselen)
{
if (p2 > p)
{
p = p2;
break;
}
p++;
}
}
if (!isspace(b))
break;
p++;
}
return p;
}
/* modify this to allow all chars for an element or attribute name*/
{
int p = p0;
while (p<parselen)
{
if (b<=' ' || b=='/' || b=='>' || b=='=')
break;
p++;
}
return p;
}
{
int p = p0;
return p0;
p++;
while ( p<parselen )
{
if (b=='"' || b=='\'')
break;
if (b=='&' && do_i_parse)
{
bool found = false;
{
if (p2>p)
{
p = p2;
found = true;
break;
}
}
if (!found)
{
error("unterminated entity");
return false;
}
}
else
{
p++;
}
}
return p;
}
{
//printf("### parseVersion: %d\n", p0);
int p = p0;
if (peek(p) != '<')
return p0;
p++;
return p0;
p++;
while (p<parselen)
{
if (ch=='?')
{
p++;
break;
}
p++;
}
if (peek(p) != '>')
return p0;
p++;
//printf("Got version:%s\n",buf.c_str());
return p;
}
{
//printf("### parseDoctype: %d\n", p0);
int p = p0;
p = skipwhite(p);
return p0;
p++;
return p0;
p++;
while (p<parselen)
{
if (ch=='>')
{
p++;
break;
}
p++;
}
//printf("Got doctype:%s\n",buf.c_str());
return p;
}
{
int p = p0;
int p2 = p;
p = skipwhite(p);
//## Get open tag
if (ch!='<')
return p0;
p++;
p = skipwhite(p);
p = getWord(p, openTagName);
//printf("####tag :%s\n", openTagName.c_str());
p = skipwhite(p);
//Add element to tree
// Get attributes
if (peek(p) != '>')
{
while (p<parselen)
{
p = skipwhite(p);
//printf("ch:%c\n",ch);
if (ch=='>')
break;
{
p++;
p = skipwhite(p);
if (ch=='>')
{
p++;
//printf("quick close\n");
return p;
}
}
if (p2==p)
break;
//printf("name:%s",buf);
p=p2;
p = skipwhite(p);
//printf("ch:%c\n",ch);
if (ch!='=')
break;
p++;
p = skipwhite(p);
// ch = parsebuf[p];
// printf("ch:%c\n",ch);
p=p2+1;
//printf("name:'%s' value:'%s'\n",attrName.c_str(),attrVal.c_str());
else
}
}
bool cdata = false;
p++;
// ### Get intervening data ### */
while (p<parselen)
{
//# COMMENT
{
p = p2;
while (p<parselen)
{
if (p2 > p)
{
p = p2;
break;
}
p++;
}
}
//# END TAG
{
break;
}
//# CDATA
if (p2 > p)
{
cdata = true;
p = p2;
continue;
}
//# CHILD ELEMENT
if (ch == '<')
{
if (p2 == p)
{
/*
printf("problem on element:%s. p2:%d p:%d\n",
openTagName.c_str(), p2, p);
*/
return p0;
}
p = p2;
continue;
}
//# ENTITY
{
bool found = false;
{
if (p2>p)
{
p = p2;
found = true;
break;
}
}
if (!found)
{
error("unterminated entity");
return -1;
}
continue;
}
//# NONE OF THE ABOVE
p++;
}/*while*/
//printf("%d : data:%s\n",p,data.c_str());
//## Get close tag
p = skipwhite(p);
if (ch != '<')
{
error("no < for end tag\n");
return p0;
}
p++;
if (ch != '/')
{
error("no / on end tag");
return p0;
}
p++;
p = skipwhite(p);
p = getWord(p, closeTagName);
if (openTagName != closeTagName)
{
error("Mismatched closing tag. Expected </%S>. Got '%S'.",
return p0;
}
p = skipwhite(p);
if (peek(p) != '>')
{
return p0;
}
p++;
// printf("close element:%s\n",closeTagName.c_str());
p = skipwhite(p);
return p;
}
{
return rootNode;
}
{
long i = 0;
for ( ; i < len ; i++)
charbuf[i] = '\0';
delete[] charbuf;
return n;
}
{
long i = 0;
for ( ; i < len ; i++)
charbuf[i] = '\0';
delete[] charbuf;
return n;
}
{
//##### LOAD INTO A CHAR BUF, THEN CONVERT TO XMLCh
if (!f)
return NULL;
{
fclose(f);
return NULL;
}
//printf("length:%d\n",filelen);
{
}
fclose(f);
/*
printf("nrbytes:%d\n",wc_count);
printf("buf:%ls\n======\n",charbuf);
*/
delete[] charbuf;
return n;
}
//########################################################################
//########################################################################
//## E N D X M L
//########################################################################
//########################################################################
//########################################################################
//########################################################################
//## U R I
//########################################################################
//########################################################################
//This would normally be a call to a UNICODE function
/**
* A class that implements the W3C URI resource reference.
*/
class URI
{
public:
typedef enum
{
SCHEME_NONE =0,
} SchemeTypes;
/**
*
*/
URI()
{
init();
}
/**
*
*/
{
init();
}
/**
*
*/
{
init();
}
/**
*
*/
{
init();
}
/**
*
*/
{
init();
return *this;
}
/**
*
*/
virtual ~URI()
{}
/**
*
*/
/**
*
*/
/**
*
*/
virtual int getScheme() const;
/**
*
*/
virtual String getSchemeStr() const;
/**
*
*/
virtual String getAuthority() const;
/**
* Same as getAuthority, but if the port has been specified
* as host:port , the port will not be included
*/
/**
*
*/
virtual int getPort() const;
/**
*
*/
/**
*
*/
virtual String getNativePath() const;
/**
*
*/
virtual bool isAbsolute() const;
/**
*
*/
virtual bool isOpaque() const;
/**
*
*/
/**
*
*/
virtual String getFragment() const;
/**
*
*/
/**
*
*/
virtual void normalize();
private:
/**
*
*/
void init()
{
parselen = 0;
schemeStr = "";
port = 0;
authority = "";
path = "";
absolute = false;
opaque = false;
query = "";
fragment = "";
}
/**
*
*/
{
}
int scheme;
bool portSpecified;
int port;
bool absolute;
bool opaque;
int peek(int p);
int parseScheme(int p);
int parseHierarchicalPart(int p0);
int parseQuery(int p0);
int parseFragment(int p0);
int parse(int p);
char *parsebuf;
int parselen;
};
typedef struct
{
int ival;
char *sval;
int port;
} LookupEntry;
LookupEntry schemes[] =
{
{ 0, NULL, 0 }
};
{
{
}
{
}
{
}
return str;
}
{
return scheme;
}
{
return schemeStr;
}
{
if (portSpecified && port>=0)
{
char buf[7];
}
return ret;
}
{
return authority;
}
{
return port;
}
{
return path;
}
{
#ifdef __WIN32__
unsigned int firstChar = 0;
{
if (path[0] == '/' &&
firstChar++;
}
{
if (ch == '/')
else
}
#else
#endif
return npath;
}
bool URI::isAbsolute() const
{
return absolute;
}
{
return opaque;
}
{
return query;
}
{
return fragment;
}
{
//### According to w3c, this is handled in 3 cases
//## 1
return other;
//## 2
{
return fragUri;
}
//## 3 http://www.ietf.org/rfc/rfc2396.txt, section 5.2
//# 3.1
{
//# 3.2
}
else
{
//# 3.3
{
}
else
{
{
}
else
}
}
return newUri;
}
/**
* This follows the Java URI algorithm:
* 1. All "." segments are removed.
* 2. If a ".." segment is preceded by a non-".." segment
* then both of these segments are removed. This step
* is repeated until it is no longer applicable.
* 3. If the path is relative, and if its first segment
* contains a colon character (':'), then a "." segment
* is prepended. This prevents a relative URI with a path
* such as "a:b/c/d" from later being re-parsed as an
* opaque URI with a scheme of "a" and a scheme-specific
* part of "b/c/d". (Deviation from RFC 2396)
*/
{
//## Collect segments
return;
bool abs = false;
unsigned int pos=0;
if (path[0]=='/')
{
abs = true;
pos++;
}
{
{
//printf("last segment:%s\n", seg.c_str());
break;
}
{
//printf("segment:%s\n", seg.c_str());
}
pos++;
}
//## Clean up (normalize) segments
bool edited = false;
{
if (s == ".")
{
edited = true;
}
else if (s == ".." &&
{
iter--; //back up, then erase two entries
edited = true;
}
else
iter++;
}
//## Rebuild path, if necessary
if (edited)
{
if (abs)
{
}
{
}
}
}
//#########################################################################
//# M E S S A G E S
//#########################################################################
{
}
{
}
//#########################################################################
//# P A R S I N G
//#########################################################################
{
if (p<0 || p>=parselen)
return -1;
return parsebuf[p];
}
{
int p = p0;
while (p < parselen)
{
if (*key == '\0')
return p;
break;
p++; key++;
}
return p0;
}
//#########################################################################
//# Parsing is performed according to:
//# http://www.gbiv.com/protocols/uri/rfc/rfc3986.html#components
//#########################################################################
{
int p = p0;
{
if (p2 > p)
{
p = p2;
return p;
}
}
return p;
}
{
int p = p0;
int ch;
//# Authority field (host and port, for example)
if (p2 > p)
{
p = p2;
portSpecified = false;
while (p < parselen)
{
if (ch == '/')
break;
else if (ch == ':')
portSpecified = true;
else if (portSpecified)
else
p++;
}
{
char *endStr;
}
}
//# Are we absolute?
{
absolute = true;
}
else if (ch == '/')
{
absolute = true;
if (p>p0) //in other words, if '/' is not the first char
opaque = true;
p++;
}
while (p < parselen)
{
break;
p++;
}
return p;
}
{
int p = p0;
if (ch != '?')
return p0;
p++;
while (p < parselen)
{
if (ch == '#')
break;
p++;
}
return p;
}
{
int p = p0;
if (ch != '#')
return p0;
p++;
while (p < parselen)
{
if (ch == '?')
break;
p++;
}
return p;
}
{
int p = p0;
int p2 = parseScheme(p);
if (p2 < 0)
{
error("Scheme");
return -1;
}
p = p2;
p2 = parseHierarchicalPart(p);
if (p2 < 0)
{
error("Hierarchical part");
return -1;
}
p = p2;
p2 = parseQuery(p);
if (p2 < 0)
{
error("Query");
return -1;
}
p = p2;
p2 = parseFragment(p);
if (p2 < 0)
{
error("Fragment");
return -1;
}
p = p2;
return p;
}
{
{
if (ch == '\\')
else
}
int p = parse(0);
normalize();
if (p < 0)
{
error("Syntax error");
return false;
}
//printf("uri:%s\n", toString().c_str());
//printf("path:%s\n", path.c_str());
return true;
}
//########################################################################
//########################################################################
//## M A K E
//########################################################################
//########################################################################
//########################################################################
//# M A K E B A S E
//########################################################################
/**
* Base class for all classes in this file
*/
class MakeBase
{
public:
MakeBase()
{}
virtual ~MakeBase()
{}
/**
* Return the URI of the file associated with this object
*/
{ return uri; }
/**
* Set the uri to the given string
*/
/**
* Resolve another path relative to this one
*/
/**
* Get an element attribute, performing substitutions if necessary
*/
/**
* Get an element value, performing substitutions if necessary
*/
protected:
/**
* The path to the file associated with this object
*/
/**
* Print a printf()-like formatted error message
*/
/**
* Print a printf()-like formatted trace message
*/
/**
* Print a printf()-like formatted trace message
*/
/**
*
*/
/**
* Break up a string into substrings delimited the characters
* in delimiters. Null-length substrings are ignored
*/
const String &delimiters);
/**
* remove leading and trailing whitespace from string
*/
/**
* Return the native format of the canonical
* path which we store
*/
/**
* Execute a shell command. Outbuf is a ref to a string
* to catch the result.
*/
/**
* List all directories in a given base and starting directory
* It is usually called like:
* bool ret = listDirectories("src", "", result);
*/
/**
* Find all files in the named directory whose short names (no path) match
* the given regex pattern
*/
/**
* Parse a <patternset>
*/
/**
* Parse a <fileset> entry, and determine which files
* should be included
*/
/**
* Return this object's property list
*/
{ return properties; }
/**
* Return a named property if found, else a null string
*/
{
return val;
}
/**
* Turn 'true' and 'false' into boolean values
*/
/**
* Create a directory, making intermediate dirs
* if necessary
*/
/**
* Delete a directory and its children if desired
*/
/**
* Copy a file from one name to another. Perform only if needed
*/
/**
* Tests is the modification date of fileA is newer than fileB
*/
private:
/**
* replace variable refs like ${a} with their values
*/
};
/**
* Print a printf()-like formatted error message
*/
{
}
/**
* Print a printf()-like formatted trace message
*/
{
//fprintf(stdout, " ");
}
/**
* Resolve another path relative to this one
*/
{
return ret;
}
/**
* Print a printf()-like formatted trace message
*/
{
}
/**
* Return the suffix, if any, of a file name
*/
{
return "";
return "";
pos++;
//trace("suffix:%s", res.c_str());
return res;
}
/**
* Break up a string into substrings delimited the characters
* in delimiters. Null-length substrings are ignored
*/
const String &delimiters)
{
{
char *p = (char *)0;
for (p=del ; *p ; p++)
if (*p == ch)
break;
if (*p)
{
{
}
}
else
{
}
}
//Add tail
{
}
return res;
}
/**
* Removes whitespace from beginning and end of a string
*/
{
if (s.size() < 1)
return s;
//Find first non-ws char
unsigned int begin = 0;
{
break;
}
//Find first non-ws char, going in reverse
{
break;
}
//trace("begin:%d end:%d", begin, end);
return res;
}
/**
* Return the native format of the canonical
* path which we store
*/
{
#ifdef __WIN32__
unsigned int firstChar = 0;
{
if (path[0] == '/' &&
firstChar++;
}
{
if (ch == '/')
else
}
return npath;
#else
return path;
#endif
}
#ifdef __WIN32__
#include <tchar.h>
static String win32LastError()
{
NULL,
dw,
0,
0, NULL );
if(p != NULL)
{ // lose CRLF
*p = _T('\0');
}
return ret;
}
#endif
/**
* Execute a system call, using pipes to send data to the
* program's stdin, and reading stdout and stderr.
*/
{
status("============ cmd ============\n%s\n=============================",
#ifdef __WIN32__
/*
I really hate having win32 code in this program, but the
read buffer in command.com and cmd.exe are just too small
for the large commands we need for compiling and linking.
*/
bool ret = true;
//# Allocate a separate buffer for safety
if (!paramBuf)
{
error("executeCommand cannot allocate command buffer");
return false;
}
//# Create pipes
{
error("executeProgram: could not create pipe");
delete[] paramBuf;
return false;
}
{
error("executeProgram: could not create pipe");
delete[] paramBuf;
return false;
}
{
error("executeProgram: could not create pipe");
delete[] paramBuf;
return false;
}
// Create the process
{
error("executeCommand : could not create process : %s",
win32LastError().c_str());
ret = false;
}
&bytesWritten, NULL))
{
error("executeCommand: could not write to pipe");
return false;
}
if (!CloseHandle(stdinWrite))
{
error("executeCommand: could not close write pipe");
return false;
}
if (!CloseHandle(stdoutWrite))
{
error("executeCommand: could not close read pipe");
return false;
}
if (!CloseHandle(stderrWrite))
{
error("executeCommand: could not close read pipe");
return false;
}
while (true)
{
//trace("## stderr");
break;
if (avail > 0)
{
char readBuf[1025];
|| bytesRead == 0)
{
break;
}
for (unsigned int i=0 ; i<bytesRead ; i++)
}
//trace("## stdout");
break;
if (avail > 0)
{
char readBuf[1025];
|| bytesRead==0)
{
break;
}
for (unsigned int i=0 ; i<bytesRead ; i++)
}
if (exitCode != STILL_ACTIVE)
break;
Sleep(100);
}
//trace("outbuf:%s", outbuf.c_str());
if (!CloseHandle(stdoutRead))
{
error("executeCommand: could not close read pipe");
return false;
}
if (!CloseHandle(stderrRead))
{
error("executeCommand: could not close read pipe");
return false;
}
//trace("exit code:%d", exitCode);
if (exitCode != 0)
{
ret = false;
}
// Clean up
return ret;
#else //do it unix-style
String s;
int errnum = 0;
if (f)
{
while (true)
{
if (ch < 0)
break;
}
}
outbuf = s;
if (errnum < 0)
{
error("exec of command '%s' failed : %s",
return false;
}
else
return true;
#endif
}
{
{
}
while (true)
{
if (!de)
break;
//Get the directory member name
if (s.size() == 0 || s[0] == '.')
continue;
{
}
{
//trace("directory: %s", childName.c_str());
return false;
}
}
return true;
}
{
{
}
while (true)
{
if (!de)
break;
//Get the directory member name
if (s.size() == 0 || s[0] == '.')
continue;
{
}
{
//trace("EXCLUDED:%s", childName.c_str());
continue;
}
{
return false;
}
{
//trace("directory: %s", childName.c_str());
return false;
}
{
}
else
{
}
}
return true;
}
{
for (int i=0 ; i<len ; i++)
{
char ch = s[i];
{
int j = i+2;
for ( ; j<len ; j++)
{
ch = s[j];
{
error("attribute %s cannot have nested variable references",
s.c_str());
return false;
}
else if (ch == '}')
{
{
}
else
{
return false;
}
break;
}
else
{
}
}
i = j;
}
else
{
}
}
return true;
}
{
return getSubstitutions(s, result);
}
{
//Replace all runs of whitespace with a single space
for (int i = 0 ; i<len ; i++)
{
char ch = s[i];
{
for ( ; i<len ; i++)
{
ch = s[i];
{
break;
}
}
}
else
{
}
}
}
/**
* Turn 'true' and 'false' into boolean values
*/
{
if (str == "true")
val = true;
else if (str == "false")
val = false;
else
{
return false;
}
return true;
}
/**
* Parse a <patternset> entry
*/
)
{
{
if (tagName == "exclude")
{
return false;
//trace("EXCLUDE: %s", fname.c_str());
}
else if (tagName == "include")
{
return false;
//trace("INCLUDE: %s", fname.c_str());
}
}
return true;
}
/**
* Parse a <fileset> entry, and determine which files
* should be included
*/
{
if (name != "fileset")
{
error("expected <fileset>");
return false;
}
//A fileset has one implied patternset
{
return false;
}
//Look for child tags, including more patternsets
{
if (tagName == "patternset")
{
{
return false;
}
}
}
//Now do the stuff
//Get the base directory for reading file names
return false;
{
return false;
}
{
}
/*
for (unsigned int i=0 ; i<result.size() ; i++)
{
trace("RES:%s", result[i].c_str());
}
*/
return true;
}
/**
* Create a directory, making intermediate dirs
* if necessary
*/
{
//trace("## createDirectory: %s", dirname.c_str());
//## first check if it exists
{
{
error("mkdir: file %s exists but is not a directory",
cnative);
return false;
}
else //exists
{
return true;
}
}
//## 2: pull off the last path segment, if any,
//## to make the dir 'above' this one, if necessary
{
if (!createDirectory(subpath))
return false;
}
//## 3: now make
{
return false;
}
return true;
}
/**
* Remove a directory recursively
*/
{
if (!dir)
{
//# Let this fail nicely.
return true;
//error("error opening directory %s : %s", dname, strerror(errno));
//return false;
}
while (true)
{
if (!de)
break;
//Get the directory member name
if (s.size() == 0 || s[0] == '.')
continue;
{
}
{
}
{
//trace("DEL dir: %s", childName.c_str());
if (!removeDirectory(childName))
{
return false;
}
}
{
}
else
{
//trace("DEL file: %s", childName.c_str());
{
error("error deleting %s : %s",
return false;
}
}
}
//Now delete the directory
{
error("could not delete directory %s : %s",
return false;
}
return true;
}
/**
* Copy a file from one name to another. Perform only if needed
*/
{
//# 1 Check up-to-date times
{
error("source file %s for copy does not exist",
return false;
}
{
return true;
}
//# 2 prepare a destination directory if necessary
{
if (!createDirectory(subpath))
return false;
}
//# 3 do the data copy
if (!srcf)
{
return false;
}
if (!destf)
{
return false;
}
{
if (ch<0)
break;
}
return true;
}
/**
* Tests is the modification of fileA is newer than fileB
*/
{
//IF source does not exist, NOT newer
{
return false;
}
//IF dest does not exist, YES, newer
{
return true;
}
//check the actual times
{
return true;
}
return false;
}
//########################################################################
//# P K G C O N F I G
//########################################################################
/**
*
*/
{
public:
/**
*
*/
{ init(); }
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
virtual ~PkgConfig()
{ }
/**
*
*/
{ return name; }
/**
*
*/
virtual String getDescription()
{ return description; }
/**
*
*/
{ return cflags; }
/**
*
*/
{ return libs; }
/**
*
*/
virtual String getVersion()
{ return version; }
/**
*
*/
virtual int getMajorVersion()
{ return majorVersion; }
/**
*
*/
virtual int getMinorVersion()
{ return minorVersion; }
/**
*
*/
virtual int getMicroVersion()
{ return microVersion; }
/**
*
*/
{ return attrs; }
/**
*
*/
{ return requireList; }
private:
void init()
{
name = "";
description = "";
cflags = "";
libs = "";
requires = "";
version = "";
majorVersion = 0;
minorVersion = 0;
microVersion = 0;
fileName = "";
requireList.clear();
}
{
}
void parseRequires();
void parseVersion();
void dumpAttrs();
int majorVersion;
int minorVersion;
int microVersion;
char *parsebuf;
int parselen;
};
/**
* Get a character from the buffer at pos. If out of range,
* return -1 for safety
*/
{
return -1;
}
/**
* Skip over all whitespace characters beginning at pos. Return
* the position of the first non-whitespace character.
*/
{
{
if (ch < 0)
break;
break;
pos++;
}
return pos;
}
/**
* Parse the buffer beginning at pos, for a word. Fill
* 'ret' with the result. Return the position after the
* word.
*/
{
{
if (ch < 0)
break;
break;
pos++;
}
return pos;
}
void PkgConfig::parseRequires()
{
return;
int pos = 0;
{
break;
//trace("val %s", val.c_str());
}
}
{
if (ends == s)
return 0L;
else
return val;
}
void PkgConfig::parseVersion()
{
return;
unsigned int pos = 0;
{
}
else
{
pos++;
{
{
}
else
{
pos++;
}
}
}
//trace("version:%d.%d.%d", majorVersion,
// minorVersion, microVersion );
}
{
init();
int pos = 0;
{
if (ch == '#')
{
//comment. eat the rest of the line
{
break;
pos++;
}
continue;
}
continue;
{
error("expected ':' or '='");
return false;
}
pos++;
{
break;
{
//# this is a ${substitution}
pos += 2;
{
if (ch < 0)
{
error("unterminated substitution");
return false;
}
else if (ch == '}')
break;
else
pos++;
}
//trace("subName:%s", subName.c_str());
//trace("subVal:%s", subVal.c_str());
}
else
pos++;
}
if (attrName == "Name")
else if (attrName == "Description")
else if (attrName == "Cflags")
else if (attrName == "Libs")
else if (attrName == "Requires")
else if (attrName == "Version")
//trace("name:'%s' value:'%s'",
// attrName.c_str(), attrVal.c_str());
}
parseVersion();
return true;
}
{
{
}
}
{
if (!f)
{
return false;
}
while (true)
{
if (ch < 0)
break;
}
fclose(f);
{
return false;
}
dumpAttrs();
return true;
}
//########################################################################
//# D E P T O O L
//########################################################################
/**
* Class which holds information for each file.
*/
class FileRec
{
public:
typedef enum
{
} FileType;
/**
* Constructor
*/
FileRec()
/**
* Copy constructor
*/
/**
* Constructor
*/
/**
* Assignment operator
*/
/**
* Destructor
*/
~FileRec()
{}
/**
* Directory part of the file name
*/
/**
* Base name, sans directory and suffix
*/
/**
* File extension, such as cpp or h
*/
/**
* Type of file: CFILE, HFILE, OFILE
*/
int type;
/**
* Used to list files ref'd by this one
*/
private:
void init()
{
}
{
}
};
/**
* Simpler dependency record
*/
class DepRec
{
public:
/**
* Constructor
*/
DepRec()
{init();}
/**
* Copy constructor
*/
/**
* Constructor
*/
/**
* Assignment operator
*/
/**
* Destructor
*/
~DepRec()
{}
/**
* Directory part of the file name
*/
/**
* Base name, without the path and suffix
*/
/**
* Suffix of the source
*/
/**
* Used to list files ref'd by this one
*/
private:
void init()
{
}
{
}
};
{
public:
/**
* Constructor
*/
DepTool()
{init();}
/**
* Copy constructor
*/
/**
* Assignment operator
*/
/**
* Destructor
*/
~DepTool()
{}
/**
* Reset this section of code
*/
virtual void init();
/**
* Reset this section of code
*/
{
}
/**
* Sets the source directory which will be scanned
*/
/**
* Returns the source directory which will be scanned
*/
virtual String getSourceDirectory()
{ return sourceDir; }
/**
* Sets the list of files within the directory to analyze
*/
/**
* Creates the list of all file names which will be
* candidates for further processing. Reads make.exclude
* to see which files for directories to leave out.
*/
virtual bool createFileList();
/**
* Generates the forward dependency list
*/
virtual bool generateDependencies();
/**
* Generates the forward dependency list, saving the file
*/
virtual bool generateDependencies(const String &);
/**
* Load a dependency file
*/
/**
* Load a dependency file, generating one if necessary
*/
/**
* Save a dependency file
*/
private:
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
FileRec *include,
int depth);
/**
*
*/
/**
*
*/
/**
*
*/
/**
* A list of all files which will be processed for
* dependencies. This is the only list that has the actual
* records. All other lists have pointers to these records.
*/
/**
* The list of .o files, and the
* dependencies upon them.
*/
int depFileSize;
char *depFileBuf;
};
/**
* Clean up after processing. Called by the destructor, but should
* also be called before the object is reused.
*/
{
sourceDir = ".";
directories.clear();
//clear refs
//clear records
}
/**
* Parse a full path name into path, base name, and suffix
*/
{
return;
{
pos++;
}
else
{
path = "";
}
{
}
//trace("parsename:%s %s %s", path.c_str(),
// basename.c_str(), suffix.c_str());
}
/**
* Generate our internal file list.
*/
bool DepTool::createFileList()
{
{
//trace("## FileName:%s", fileName.c_str());
{
}
{
}
}
return false;
return true;
}
/**
* Get a character from the buffer at pos. If out of range,
* return -1 for safety
*/
{
if (pos>depFileSize)
return -1;
return depFileBuf[pos];
}
/**
* Skip over all whitespace characters beginning at pos. Return
* the position of the first non-whitespace character.
*/
{
while (pos < depFileSize)
{
if (ch < 0)
break;
break;
pos++;
}
return pos;
}
/**
* Parse the buffer beginning at pos, for a word. Fill
* 'ret' with the result. Return the position after the
* word.
*/
{
while (pos < depFileSize)
{
if (ch < 0)
break;
break;
pos++;
}
return pos;
}
/**
* Return whether the sequence of characters in the buffer
* beginning at pos match the key, for the length of the key
*/
{
while (*key)
{
return false;
}
return true;
}
/**
* Add an include file name to a file record. If the name
* is not found in allFiles explicitly, try prepending include
* directory names to it and try again.
*/
{
{
//h file in same dir
//trace("local: '%s'", iname.c_str());
return true;
}
else
{
//look in other dirs
{
{
//trace("other: '%s'", iname.c_str());
return true;
}
}
}
return true;
}
/**
* Lightly parse a file to find the #include directives. Do
* a bit of state machine stuff to make sure that the directive
* is valid. (Like not in a comment).
*/
{
{
}
if (!f)
{
return false;
}
while (true)
{
if (ch < 0)
break;
}
fclose(f);
int pos = 0;
while (pos < depFileSize)
{
//trace("p:%c", get(pos));
//# Block comment
{
pos += 2;
while (pos < depFileSize)
{
{
pos += 2;
break;
}
else
pos++;
}
}
//# Line comment
{
pos += 2;
while (pos < depFileSize)
{
{
pos++;
break;
}
else
pos++;
}
}
//# #include! yaay
{
pos += 8;
{
}
}
else
{
pos++;
}
}
return true;
}
/**
* Recursively check include lists to find all files in allFiles to which
* a given file is dependent.
*/
FileRec *include,
int depth)
{
{
{
//trace("file '%s' already seen", fname.c_str());
continue;
}
}
return true;
}
/**
* Generate the file dependency list.
*/
bool DepTool::generateDependencies()
{
//# First pass. Scan for all includes
{
{
//quit?
}
}
//# Second pass. Scan for all includes
{
{
//add the .c file first? no, don't
//ofile->files[cFileName] = include;
//trace("ofile:%s", fname.c_str());
processDependency(ofile, include, 0);
}
}
return true;
}
/**
* High-level call to generate deps and optionally save them
*/
{
if (!createFileList())
return false;
if (!generateDependencies())
return false;
if (!saveDepFile(fileName))
return false;
return true;
}
/**
* This saves the dependency cache.
*/
{
if (!f)
{
}
fprintf(f, "<?xml version='1.0'?>\n");
fprintf(f, "<!--\n");
fprintf(f, "########################################################\n");
fprintf(f, "## File: build.dep\n");
fprintf(f, "########################################################\n");
fprintf(f, "-->\n");
{
{
fprintf(f, "<object path='%s' name='%s' suffix='%s'>\n",
{
}
fprintf(f, "</object>\n\n");
}
}
fprintf(f, "</dependencies>\n");
fprintf(f, "\n");
fprintf(f, "<!--\n");
fprintf(f, "########################################################\n");
fprintf(f, "## E N D\n");
fprintf(f, "########################################################\n");
fprintf(f, "-->\n");
fclose(f);
return true;
}
/**
* This loads the dependency cache.
*/
{
if (!root)
{
return result;
}
{
error("Main xml element should be <dependencies>");
delete root;
return result;
}
//########## Start parsing
{
if (tagName == "object")
{
//trace("object:%s", objName.c_str());
//########## DESCRIPTION
{
if (tagName == "dep")
{
//trace(" dep:%s", depName.c_str());
}
}
//Insert into the result list, in a sorted manner
bool inserted = false;
{
{
inserted = true;
break;
}
}
if (!inserted)
}
}
delete root;
return result;
}
/**
* This loads the dependency cache.
*/
{
{
}
return result;
}
//########################################################################
//# T A S K
//########################################################################
//forward decl
class Target;
class Make;
/**
*
*/
{
public:
typedef enum
{
} TaskType;
/**
*
*/
{ init(); }
/**
*
*/
/**
*
*/
/**
*
*/
virtual ~Task()
{ }
/**
*
*/
{ return parent; }
/**
*
*/
virtual int getType()
{ return type; }
/**
*
*/
/**
*
*/
{ return name; }
/**
*
*/
virtual bool execute()
{ return true; }
/**
*
*/
{ return true; }
/**
*
*/
protected:
void init()
{
name = "none";
}
{
}
{
return str;
}
int type;
};
/**
* Run the "ar" command to archive .o's into a .a
*/
{
public:
{
command = "ar crv";
}
virtual ~TaskAr()
{}
virtual bool execute()
{
//trace("###########HERE %d", fileSet.size());
bool doit = false;
//trace("ar fullout: %s", fullOut.c_str());
{
if (fileSetDir.size()>0)
{
}
//trace("ar : %s/%s", fullOut.c_str(), fullName.c_str());
doit = true;
}
//trace("Needs it:%d", doit);
if (!doit)
{
return true;
}
{
if (fileSetDir.size()>0)
{
}
}
{
return false;
}
return true;
}
{
return false;
{
if (tagName == "fileset")
{
return false;
}
}
return true;
}
private:
};
/**
* This task runs the C/C++ compiler. The compiler is invoked
* for all .c or .cpp files which are newer than their correcsponding
* .o files.
*/
{
public:
{
ccCommand = "gcc";
cxxCommand = "g++";
source = ".";
dest = ".";
flags = "";
defines = "";
includes = "";
sourceFiles.clear();
}
virtual ~TaskCC()
{}
virtual bool execute()
{
{
}
{
}
{
}
{
{
}
}
{
//## Select command
|| sfx == "CC")
//## Make paths
{
}
//## Make sure destination directory exists
if (!createDirectory(destPath))
return false;
//## Check whether it needs to be done
{
//trace("%s skipped", srcFullName.c_str());
continue;
}
//## Assemble the command
//## Execute the command
{
return false;
}
}
return true;
}
{
String s;
return false;
return false;
return false;
if (s.size()>0) cxxCommand = s;
return false;
{
if (tagName == "flags")
{
return false;
}
else if (tagName == "includes")
{
return false;
}
else if (tagName == "defines")
{
return false;
}
else if (tagName == "fileset")
{
return false;
}
}
return true;
}
protected:
};
/**
*
*/
{
public:
typedef enum
{
} CopyType;
{
verbose = false;
haveFileSet = false;
}
virtual ~TaskCopy()
{}
virtual bool execute()
{
switch (cptype)
{
case CP_TOFILE:
{
{
//trace("copy %s to file %s", fullSource.c_str(),
// fullDest.c_str());
{
return true;
}
return false;
status(" : 1 file copied");
}
return true;
}
case CP_TODIR:
{
if (haveFileSet)
{
int nrFiles = 0;
{
if (fileSetDir.size()>0)
{
}
//Get the immediate parent directory's base name
baseFileSetDir.size());
//Now make the new path
{
}
if (baseFileSetDir.size()>0)
{
}
//trace("fileName:%s", fileName.c_str());
//trace("copy %s to new dir : %s", fullSource.c_str(),
// fullDest.c_str());
{
//trace("copy skipping %s", fullSource.c_str());
continue;
}
return false;
nrFiles++;
}
}
else //file source
{
//For file->dir we want only the basename of
//the source appended to the dest dir
{
}
//trace("copy %s to new dir : %s", fullSource.c_str(),
// fullDest.c_str());
{
return true;
}
return false;
status(" : 1 file copied");
}
return true;
}
}
return true;
}
{
return false;
return false;
if (toFileName.size() > 0)
return false;
return false;
return false;
haveFileSet = false;
{
if (tagName == "fileset")
{
{
error("problem getting fileset");
return false;
}
haveFileSet = true;
}
}
//Perform validity checks
{
error("<copy> can only have one of : file= and <fileset>");
return false;
}
{
error("<copy> can only have one of : tofile= or todir=");
return false;
}
{
error("a <copy> task with a <fileset> must have : todir=");
return false;
}
{
error("<copy> tofile= must be associated with : file=");
return false;
}
{
error("<copy> todir= must be associated with : file= or <fileset>");
return false;
}
return true;
}
private:
int cptype;
bool verbose;
bool haveFileSet;
};
/**
*
*/
class TaskDelete : public Task
{
public:
typedef enum
{
} DeleteType;
{
type = TASK_DELETE;
name = "delete";
verbose = false;
quiet = false;
failOnError = true;
}
virtual ~TaskDelete()
{}
virtual bool execute()
{
switch (delType)
{
case DEL_FILE:
{
//does not exist
return true;
//exists but is not a regular file
{
error("<delete> failed. '%s' exists and is not a regular file",
fname);
return false;
}
{
return false;
}
return true;
}
case DEL_DIR:
{
if (!removeDirectory(fullDir))
return false;
return true;
}
}
return true;
}
{
return false;
return false;
{
error("<delete> can only have one attribute of file= or dir=");
return false;
}
return false;
return false;
return false;
return false;
return false;
return false;
return true;
}
private:
int delType;
bool verbose;
bool quiet;
bool failOnError;
};
/**
*
*/
{
public:
virtual ~TaskJar()
{}
virtual bool execute()
{
return true;
}
{
return true;
}
};
/**
*
*/
{
public:
virtual ~TaskJavac()
{}
virtual bool execute()
{
return true;
}
{
return true;
}
};
/**
*
*/
{
public:
{
command = "g++";
}
virtual ~TaskLink()
{}
virtual bool execute()
{
bool doit = false;
{
if (fileSetDir.size()>0)
{
}
doit = true;
}
if (!doit)
{
//trace("link not needed");
return true;
}
//trace("LINK cmd:%s", cmd.c_str());
{
return false;
}
return true;
}
{
return false;
return false;
{
if (tagName == "fileset")
{
return false;
}
else if (tagName == "flags")
{
return false;
}
else if (tagName == "libs")
{
return false;
}
}
return true;
}
private:
};
/**
* Create a named directory
*/
{
public:
virtual ~TaskMkDir()
{}
virtual bool execute()
{
//trace("fullDir:%s", fullDir.c_str());
if (!createDirectory(fullDir))
return false;
return true;
}
{
return false;
{
error("<mkdir> requires 'dir=\"dirname\"' attribute");
return false;
}
//trace("dirname:%s", dirName.c_str());
return true;
}
private:
};
/**
* Create a named directory
*/
class TaskMsgFmt: public Task
{
public:
{
type = TASK_MSGFMT;
name = "msgfmt";
command = "msgfmt";
}
virtual ~TaskMsgFmt()
{}
virtual bool execute()
{
//trace("msgfmt: %d", fileSet.size());
{
continue;
if (fileSetDir.size()>0)
{
}
{
}
{
//trace("skip %s", fullSource.c_str());
continue;
}
if (pos>0)
{
if (!createDirectory(fullDestPath))
return false;
}
{
return false;
}
}
return true;
}
{
return false;
{
if (tagName == "fileset")
{
return false;
}
}
return true;
}
private:
};
/**
* Process an archive to allow random access
*/
class TaskRanlib : public Task
{
public:
virtual ~TaskRanlib()
{}
virtual bool execute()
{
//trace("fullDir:%s", fullDir.c_str());
return false;
return true;
}
{
return false;
{
error("<ranlib> requires 'file=\"fileNname\"' attribute");
return false;
}
return true;
}
private:
};
/**
* Run the "ar" command to archive .o's into a .a
*/
{
public:
{
command = "windres -o";
}
virtual ~TaskRC()
{}
virtual bool execute()
{
return true;
{
return false;
}
return true;
}
{
return false;
return false;
return false;
{
if (tagName == "flags")
{
return false;
}
}
return true;
}
private:
};
/**
* Strip an executable
*/
{
public:
virtual ~TaskStrip()
{}
virtual bool execute()
{
//trace("fullDir:%s", fullDir.c_str());
return false;
return true;
}
{
return false;
{
error("<strip> requires 'file=\"fileNname\"' attribute");
return false;
}
return true;
}
private:
};
/**
*
*/
class TaskTstamp : public Task
{
public:
virtual ~TaskTstamp()
{}
virtual bool execute()
{
return true;
}
{
trace("tstamp parse");
return true;
}
};
/**
*
*/
{
//trace("task:%s", tagName.c_str());
if (tagName == "ar")
else if (tagName == "cc")
else if (tagName == "copy")
else if (tagName == "delete")
else if (tagName == "jar")
else if (tagName == "javac")
else if (tagName == "link")
else if (tagName == "mkdir")
else if (tagName == "msgfmt")
else if (tagName == "ranlib")
else if (tagName == "rc")
else if (tagName == "strip")
else if (tagName == "tstamp")
else
{
return NULL;
}
{
delete task;
return NULL;
}
return task;
}
//########################################################################
//# T A R G E T
//########################################################################
/**
*
*/
{
public:
/**
*
*/
{ init(); }
/**
*
*/
/**
*
*/
/**
*
*/
virtual ~Target()
{ cleanup() ; }
/**
*
*/
{ return parent; }
/**
*
*/
{ return name; }
/**
*
*/
/**
*
*/
virtual String getDescription()
{ return description; }
/**
*
*/
{ description = val; }
/**
*
*/
/**
*
*/
/**
*
*/
{ return deps; }
/**
*
*/
{ return ifVar; }
/**
*
*/
/**
*
*/
{ return unlessVar; }
/**
*
*/
/**
*
*/
/**
*
*/
{ return tasks; }
private:
void init()
{
}
void cleanup()
{
}
{
//parent = other.parent;
}
};
//########################################################################
//# M A K E
//########################################################################
/**
*
*/
{
public:
/**
*
*/
Make()
{ init(); }
/**
*
*/
/**
*
*/
/**
*
*/
virtual ~Make()
{ cleanup(); }
/**
*
*/
{ return targets; }
/**
*
*/
bool run();
/**
*
*/
private:
/**
*
*/
void init();
/**
*
*/
void cleanup();
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
bool execute();
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
bool parseFile();
/**
*
*/
//###############
//# Fields
//###############
//std::vector<Property> properties;
};
//########################################################################
//# C L A S S M A I N T E N A N C E
//########################################################################
/**
*
*/
{
projectName = "";
currentTarget = "";
defaultTarget = "";
specifiedTarget = "";
baseDir = "";
description = "";
envAlias = "";
properties.clear();
delete allTasks[i];
}
/**
*
*/
{
delete allTasks[i];
}
/**
*
*/
{
}
//########################################################################
//# U T I L I T Y T A S K S
//########################################################################
/**
* Perform a file globbing
*/
{
return res;
}
//########################################################################
//# P U B L I C A P I
//########################################################################
/**
*
*/
{
//First get any dependencies for this target
{
//Did we do it already? Skip
continue;
{
error("Target '%s' dependency '%s' not found",
return false;
}
{
return false;
}
}
//Now let's do the tasks
{
{
return false;
}
}
return true;
}
/**
* Main execute() method. Start here and work
* up the dependency tree
*/
{
status("######## EXECUTE");
//Determine initial target
if (specifiedTarget.size()>0)
{
}
else if (defaultTarget.size()>0)
{
}
else
{
error("execute: no specified or default target requested");
return false;
}
{
error("Initial target '%s' not found",
currentTarget.c_str());
return false;
}
//Now run
{
return false;
}
status("######## EXECUTE COMPLETE");
return true;
}
/**
*
*/
{
{
//First thing entered was the starting Target
{
error("Circular dependency '%s' found at '%s'",
{
}
return false;
}
{
error("Target '%s' dependency '%s' not found",
return false;
}
{
return false;
}
}
return true;
}
{
int p = pos;
while (p < len)
{
break;
p++;
}
return p;
}
/**
*
*/
{
if (!f)
{
return false;
}
int linenr = 0;
while (!feof(f))
{
char buf[256];
break;
linenr++;
s = trim(s);
if (len == 0)
continue;
if (s[0] == '#')
continue;
int p = 0;
if (p2 <= p)
{
error("property file %s, line %d: expected keyword",
return false;
}
{
}
//skip whitespace
if (!isspace(s[p]))
break;
if (p>=len || s[p]!='=')
{
error("property file %s, line %d: expected '='",
return false;
}
p++;
//skip whitespace
for ( ; p<len ; p++)
if (!isspace(s[p]))
break;
/* This way expects a word after the =
p2 = getword(p, s, val);
if (p2 <= p)
{
error("property file %s, line %d: expected value",
fileName.c_str(), linenr);
return false;
}
*/
// This way gets the rest of the line after the =
if (p>=len)
{
error("property file %s, line %d: expected value",
return false;
}
continue;
}
fclose(f);
return true;
}
/**
*
*/
{
{
if (attrName == "name")
{
return false;
{
continue;
}
return false;
{
//TODO: process a path relative to build.xml
continue;
}
}
else if (attrName == "file")
{
return false;
{
}
return false;
}
else if (attrName == "environment")
{
{
error("environment property can only be set once");
return false;
}
}
}
return true;
}
/**
*
*/
{
status("######## PARSE");
if (!root)
{
error("Could not open %s for reading",
return false;
}
{
error("Main xml element should be <project>");
delete root;
return false;
}
//########## Project attributes
if (s.size() > 0)
projectName = s;
if (s.size() > 0)
defaultTarget = s;
if (s.size() > 0)
baseDir = s;
//######### PARSE MEMBERS
{
//########## DESCRIPTION
if (tagName == "description")
{
}
//######### PROPERTY
else if (tagName == "property")
{
if (!parseProperty(elem))
return false;
}
//######### TARGET
else if (tagName == "target")
{
{
if (!task)
return false;
}
//Check name
{
error("no name for target");
return false;
}
//Check for duplicate name
{
return false;
}
//more work than targets[tname]=target, but avoids default allocator
}
}
{
{
return false;
}
}
delete root;
status("######## PARSE COMPLETE");
return true;
}
/**
*
*/
{
if (!parseFile())
return false;
if (!execute())
return false;
return true;
}
/**
*
*/
{
status("##################################");
status("# BuildTool");
status("# version 0.2");
status("##################################");
if (!run())
return false;
status("##################################");
status("# BuildTool Completed");
status("##################################");
return true;
}
}// namespace buildtool
//########################################################################
//# M A I N
//########################################################################
/**
* Format an error message in printf() style
*/
{
}
/**
* Compare a buffer with a key, for the length of the key
*/
{
for (int i=0 ; key[i] ; i++)
{
return false;
}
return true;
}
/**
* Parse the command-line args, get our options,
* and run this thing
*/
{
if (argc < 1)
{
error("Cannot parse arguments");
return false;
}
//char *progName = argv[0];
for (int i=1 ; i<argc ; i++)
{
{
{
}
else
{
return false;
}
}
{
{
if (0)//put options here
{
}
else
{
return false;
}
}
}
else
{
}
}
//We have the options. Now execute them
{
}
return false;
return true;
}
/*
static bool runMake()
{
buildtool::Make make;
if (!make.run())
return false;
return true;
}
static bool pkgConfigTest()
{
buildtool::PkgConfig pkgConfig;
if (!pkgConfig.readFile("gtk+-2.0.pc"))
return false;
return true;
}
static bool depTest()
{
buildtool::DepTool deptool;
if (!deptool.generateDependencies("build.dep"))
return false;
std::vector<buildtool::DepRec> res =
deptool.loadDepFile("build.dep");
if (res.size() == 0)
return false;
return true;
}
static bool popenTest()
{
buildtool::Make make;
buildtool::String out, err;
bool ret = make.executeCommand("gcc xx.cpp", "", out, err);
return true;
}
static bool propFileTest()
{
buildtool::Make make;
make.parsePropertyFile("test.prop", "test.");
return true;
}
*/
{
return 1;
/*
if (!popenTest())
return 1;
if (!depTest())
return 1;
if (!propFileTest())
return 1;
if (runMake())
return 1;
*/
return 0;
}
//########################################################################
//# E N D
//########################################################################