/**
* Simple build automation tool.
*
* Authors:
* Bob Jamison
* Jasper van de Gronde
* Johan Engelen
*
* Copyright (C) 2006-2008 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
*/
/**
* To use this file, compile with:
* <pre>
* g++ -O3 buildtool.cpp -o btool.exe -fopenmp
* (or whatever your compiler might be)
* Then
* btool
* or
* btool {target}
*
* Note: if you are using MinGW, and a not very recent version of it,
* gettimeofday() might be missing. If so, just build this file with
* this command:
* g++ -O3 -DNEED_GETTIMEOFDAY buildtool.cpp -o btool.exe -fopenmp
*
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
#include <utime.h>
#include <dirent.h>
#include <iostream>
#include <list>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#ifdef __WIN32__
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#include <windows.h>
#endif
#include <errno.h>
//########################################################################
//# Definition of gettimeofday() for those who don't have it
//########################################################################
#ifdef NEED_GETTIMEOFDAY
struct timezone {
};
{
if (!tv)
return (-1);
if (tz)
{
}
return 0;
}
#endif
namespace buildtool
{
//########################################################################
//########################################################################
//## R E G E X P
//########################################################################
//########################################################################
/**
* This is the SLRE (Super Light Regular Expression library)
* SLRE is an ISO C library that implements a subset of Perl
* regular expression syntax.
*
* See https://github.com/cesanta/slre for details
*
* It's clean code and small size allow us to
* embed it in BuildTool without adding a dependency
*
*/
//begin slre.h
/*
* Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
* Copyright (c) 2013 Cesanta Software Limited
* All rights reserved
*
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this library under the terms of the GNU General
* Public License, 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.
*
* Alternatively, you can license this library under a commercial
* license, as set out in <http://cesanta.com/products.html>.
*/
/*
* This is a regular expression library that implements a subset of Perl RE.
* Please refer to README.md for a detailed reference.
*/
#ifndef SLRE_HEADER_DEFINED
#define SLRE_HEADER_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
struct slre_cap {
const char *ptr;
int len;
};
/* Possible flags for slre_match() */
/* slre_match() failure codes */
#ifdef __cplusplus
}
#endif
#endif /* SLRE_HEADER_DEFINED */
//end slre.h
//start slre.c
/*
* Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
* Copyright (c) 2013 Cesanta Software Limited
* All rights reserved
*
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. For the terms of this
* license, see <http://www.gnu.org/licenses/>.
*
* You are free to use this library under the terms of the GNU General
* Public License, 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.
*
* Alternatively, you can license this library under a commercial
* license, as set out in <http://cesanta.com/products.html>.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//#include "slre.h"
#ifndef ARRAY_SIZE
#endif
#ifdef SLRE_DEBUG
#else
#define DBG(x)
#endif
struct bracket_pair {
};
struct branch {
/* array defined below */
};
struct regex_info {
/*
* Describes all bracket pairs in the regular expression.
* First entry is always present, and grabs the whole regex.
*/
int num_brackets;
/*
* Describes alternations ('|' operators) in the regular expression.
* Each branch falls into a specific branch pair.
*/
int num_branches;
/* Array of captures provided by the user */
int num_caps;
/* E.g. SLRE_IGNORE_CASE. See enum below */
int flags;
};
static int is_metacharacter(const unsigned char *s) {
}
}
int len = 0;
}
}
}
}
static int toi(int x) {
}
static int hextoi(const unsigned char *s) {
}
struct regex_info *info) {
int result = 0;
switch (*re) {
case '\\':
/* Metacharacters */
switch (re[1]) {
case 'x':
/* Match byte, \xHH where HH is hexadecimal byte representaion */
result++;
break;
default:
/* Valid metacharacter check is done in bar() */
result++;
break;
}
break;
case '.': result++; break;
default:
} else {
}
result++;
break;
}
return result;
}
struct regex_info *info) {
/* Support character range */
len += 3;
} else {
}
}
}
/* i is offset in re, j is offset in s, bi is brackets index */
int i, j, n, step;
/* Handle quantifiers. Get the length of the chunk. */
i++;
/* Points to the regexp code after the quantifier */
non_greedy = 1;
ni++;
}
do {
}
/* After quantifier, there is nothing */
/* Regex after quantifier matched */
}
if (nj > j && non_greedy) break;
} while (n1 > 0);
/*
* Even if we found one or more pattern, this branch will be executed,
* changing the next captures.
*/
}
/* If while loop body above was not executed for the * quantifier, */
/* make sure the rest of the regex matches */
/* Returning here cause we've matched the rest of RE already */
return nj;
}
continue;
}
if (re[i] == '[') {
FAIL_IF(n <= 0, SLRE_NO_MATCH);
j += n;
} else if (re[i] == '(') {
n = SLRE_NO_MATCH;
bi++;
DBG(("CAPTURING [%.*s] [%.*s] [%s]\n",
/* Nothing follows brackets */
} else {
int j2;
}
}
FAIL_IF(n < 0, n);
}
j += n;
} else if (re[i] == '^') {
FAIL_IF(j != 0, SLRE_NO_MATCH);
} else if (re[i] == '$') {
} else {
FAIL_IF(n <= 0, n);
j += n;
}
}
return j;
}
/* Process branch points */
const char *p;
do {
return result;
}
for (i = 0; i <= s_len; i++) {
if (result >= 0) {
result += i;
break;
}
if (is_anchored) break;
}
return result;
}
int i, j;
/* First, sort branches. Must be stable, no qsort. Use bubble algo. */
for (i = 0; i < info->num_branches; i++) {
}
}
}
/*
* For each bracket, set their branch points. This way, for every bracket
* (i.e. every chunk of regex) we know all branch points before matching.
*/
for (i = j = 0; i < info->num_brackets; i++) {
j++;
}
}
}
struct regex_info *info) {
/* First bracket captures everything */
/* Make a single pass over regex string, memorize brackets and branches */
if (re[i] == '|') {
info->num_branches++;
} else if (re[i] == '\\') {
/* Hex digit specification must follow */
} else {
}
} else if (re[i] == '(') {
depth++; /* Order is important here. Depth increments first. */
info->num_brackets++;
} else if (re[i] == ')') {
DBG(("SETTING BRACKET %d [%.*s]\n",
depth--;
}
}
}
/* Initialize info structure */
}
//end slre.c
//########################################################################
//########################################################################
//## E N D R E G E X P
//########################################################################
//########################################################################
//########################################################################
//########################################################################
//## 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; }
{ return namespaceURI; }
protected:
{
}
};
class Attribute
{
public:
{}
{
}
{
}
{
return *this;
}
virtual ~Attribute()
{}
{ return name; }
{ return value; }
protected:
{
}
};
class Element
{
friend class Parser;
public:
Element()
{
init();
}
{
init();
}
{
init();
}
{
}
{
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();
int getLine()
{ return line; }
protected:
void init()
{
line = 0;
}
{
}
int line;
};
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(int p);
int parseVersion(int p0);
int parseDoctype(int p0);
bool keepGoing;
int parselen;
int currentPosition;
};
//########################################################################
//# E L E M E N T
//########################################################################
{
{
}
return elem;
}
{
{
}
}
{
return res;
}
{
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);
{
fprintf(f," %s=\"%s\"",
}
{
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
{
const char *escaped;
char value;
} EntityEntry;
{
{ "&" , '&' },
{ "<" , '<' },
{ ">" , '>' },
{ "'", '\'' },
{ """, '"' },
{ NULL , '\0' }
};
/**
* Removes whitespace from beginning and end of a string
*/
{
if (s.size() < 1)
return s;
//Find first non-ws char
{
break;
}
//Find first non-ws char, going in reverse
{
break;
}
//trace("begin:%d end:%d", begin, end);
return res;
}
{
int count = 0;
{
count++;
}
return count;
}
{
for (long i=0 ; i<pos ; i++)
{
{
col = 0;
line ++;
}
else
col++;
}
}
{
int lineNr;
int 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;
//int line, col;
//getLineAndColumn(p, &line, &col);
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;
const char *sval;
int port;
} LookupEntry;
{
{ 0, NULL, 0 }
};
{
{
}
{
}
{
}
return str;
}
{
return scheme;
}
{
return schemeStr;
}
{
if (portSpecified && port>=0)
{
}
return ret;
}
{
return authority;
}
{
return port;
}
{
return path;
}
{
#ifdef __WIN32__
{
if (path[0] == '/' &&
firstChar++;
}
{
if (ch == '/')
else
}
#else
#endif
return npath;
}
{
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;
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;
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;
}
{
init();
{
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
//########################################################################
//########################################################################
//########################################################################
//# Stat cache to speed up stat requests
//########################################################################
struct StatResult {
int result;
};
//printf("Stat path: %s\n", f.c_str());
std::pair<statCacheType::iterator, bool> result = statCache.insert(statCacheType::value_type(f, StatResult()));
}
}
//printf("Removing from cache: %s\n", f.c_str());
}
//########################################################################
//# Dir cache to speed up dir requests
//########################################################################
/*struct DirListing {
bool available;
std::vector<String> files;
std::vector<String> dirs;
};
typedef std::map<String, DirListing > dirCacheType;
static dirCacheType dirCache;
static const DirListing &cachedDir(String fullDir)
{
String dirNative = getNativePath(fullDir);
std::pair<dirCacheType::iterator,bool> result = dirCache.insert(dirCacheType::value_type(dirNative, DirListing()));
if (result.second) {
DIR *dir = opendir(dirNative.c_str());
if (!dir)
{
error("Could not open directory %s : %s",
dirNative.c_str(), strerror(errno));
result.first->second.available = false;
}
else
{
result.first->second.available = true;
while (true)
{
struct dirent *de = readdir(dir);
if (!de)
break;
//Get the directory member name
String s = de->d_name;
if (s.size() == 0 || s[0] == '.')
continue;
String childName;
if (dirName.size()>0)
{
childName.append(dirName);
childName.append("/");
}
childName.append(s);
String fullChild = baseDir;
fullChild.append("/");
fullChild.append(childName);
if (isDirectory(fullChild))
{
//trace("directory: %s", childName.c_str());
if (!listFiles(baseDir, childName, res))
return false;
continue;
}
else if (!isRegularFile(fullChild))
{
error("unknown file:%s", childName.c_str());
return false;
}
//all done!
res.push_back(childName);
}
closedir(dir);
}
}
return result.first->second;
}*/
//########################################################################
//# F I L E S E T
//########################################################################
/**
* This is the descriptor for a <fileset> item
*/
class FileSet
{
public:
/**
*
*/
FileSet()
{}
/**
*
*/
/**
*
*/
/**
*
*/
virtual ~FileSet()
{}
/**
*
*/
{ return directory; }
/**
*
*/
/**
*
*/
/**
*
*/
{ return files; }
/**
*
*/
/**
*
*/
{ return includes; }
/**
*
*/
/**
*
*/
{ return excludes; }
/**
*
*/
/**
*
*/
/**
*
*/
void clear()
{
directory = "";
}
private:
{
}
};
//########################################################################
//# F I L E L I S T
//########################################################################
/**
* This is a simpler, explicitly-named list of files
*/
class FileList
{
public:
/**
*
*/
FileList()
{}
/**
*
*/
/**
*
*/
/**
*
*/
virtual ~FileList()
{}
/**
*
*/
{ return directory; }
/**
*
*/
/**
*
*/
/**
*
*/
{ return files; }
/**
*
*/
/**
*
*/
/**
*
*/
void clear()
{
directory = "";
}
private:
{
}
};
//########################################################################
//# M A K E B A S E
//########################################################################
/**
* Base class for all classes in this file
*/
class MakeBase
{
public:
MakeBase()
{ line = 0; }
virtual ~MakeBase()
{}
/**
* Return the URI of the file associated with this object
*/
{ return uri; }
/**
* Set the uri to the given string
*/
/**
* Set the number of threads that can be used
*/
{ numThreads = num; }
/**
* Resolve another path relative to this one
*/
/**
* replace variable refs like ${a} with their values
* Assume that the string has already been syntax validated
*/
/**
* replace variable refs like ${a} with their values
* return true or false
* Assume that the string has already been syntax validated
*/
/**
* replace variable refs like ${a} with their values
* return the value parsed as an integer
* Assume that the string has already been syntax validated
*/
/**
* Get an element attribute, performing substitutions if necessary
*/
/**
* Get an element value, performing substitutions if necessary
*/
/**
* Set the current line number in the file
*/
/**
* Get the current line number in the file
*/
int getLine()
{ return line; }
/**
* Set a property to a given value
*/
{
}
/**
* Return a named property is found, else a null string
*/
{
return String();
return sval;
}
/**
* Return true if a named property is found, else false
*/
{
return false;
return true;
}
protected:
/**
* The path to the file associated with this object
*/
/**
* The number of threads that can be used
*/
static int numThreads;
/**
* If this prefix is seen in a substitution, use an environment
* variable.
* example: <property environment="env"/>
* ${env.JAVA_HOME}
*/
/**
* If this prefix is seen in a substitution, use as a
* pkg-config 'all' query
* example: <property pkg-config="pc"/>
* ${pc.gtkmm}
*/
/**
* If this prefix is seen in a substitution, use as a
* pkg-config 'cflags' query
* example: <property pkg-config="pcc"/>
* ${pcc.gtkmm}
*/
/**
* If this prefix is seen in a substitution, use as a
* pkg-config 'libs' query
* example: <property pkg-config-libs="pcl"/>
* ${pcl.gtkmm}
*/
/**
* If this prefix is seen in a substitution, use as a
* Bazaar "bzr revno" query
* example: <property subversion="svn"/> ???
* ${bzr.Revision}
*/
/**
* Print a printf()-like formatted error message
*/
/**
* Print a printf()-like formatted trace message
*/
/**
* Show target status
*/
void targetstatus(const char *fmt, ...);
/**
* Print a printf()-like formatted trace message
*/
/**
* Check if a given string matches a given regex pattern
*/
/**
*
*/
/**
* Break up a string into substrings delimited the characters
* in delimiters. Null-length substrings are ignored
*/
const String &delimiters);
/**
* replace runs of whitespace with a space
*/
/**
* remove leading whitespace from each line
*/
/**
* remove leading and trailing whitespace from string
*/
/**
* Return a lower case version of the given 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
*/
/**
* Perform a listing for a fileset
*/
/**
* Parse a <patternset>
*/
/**
* Parse a <fileset> entry, and determine which files
* should be included
*/
/**
* Parse a <filelist> entry
*/
/**
* Return this object's property list
*/
{ return properties; }
/**
* 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
*/
/**
* Delete a file
*/
/**
* Tests if the file exists
*/
/**
* Tests if the file exists and is a regular file
*/
/**
* Tests if the file exists and is a directory
*/
/**
* Tests is the modification date of fileA is newer than fileB
*/
private:
int query,
/**
* utility method to query for "all", "cflags", or "libs" for this package and its
* dependencies. 0, 1, 2
*/
/**
* replace a variable ref like ${a} with a value
*/
/**
* called by getSubstitutions(). This is in case a looked-up string
* has substitutions also.
*/
/**
* replace variable refs in a string like ${a} with their values
*/
int line;
};
/**
* Define the pkg-config class here, since it will be used in MakeBase method
* implementations.
*/
{
public:
/**
*
*/
{
path = ".";
prefix = "/target";
init();
}
/**
*
*/
/**
*
*/
/**
*
*/
virtual ~PkgConfig()
{ }
/**
*
*/
{ return name; }
/**
*
*/
{ return path; }
/**
*
*/
/**
*
*/
{ return prefix; }
/**
* Allow the user to override the prefix in the file
*/
/**
*
*/
{ return description; }
/**
*
*/
{ return cflags; }
/**
*
*/
{ return libs; }
/**
*
*/
{
return ret;
}
/**
*
*/
{ return version; }
/**
*
*/
virtual int getMajorVersion()
{ return majorVersion; }
/**
*
*/
virtual int getMinorVersion()
{ return minorVersion; }
/**
*
*/
virtual int getMicroVersion()
{ return microVersion; }
/**
*
*/
{ return attrs; }
/**
*
*/
{ return requireList; }
/**
* Read a file for its details
*/
/**
* Read a file for its details
*/
private:
void init()
{
//do not set path and prefix here
name = "";
description = "";
cflags = "";
libs = "";
requires = "";
version = "";
majorVersion = 0;
minorVersion = 0;
microVersion = 0;
fileName = "";
requireList.clear();
}
{
}
/**
* Very important
*/
bool parseRequires();
void parseVersion();
void dumpAttrs();
int majorVersion;
int minorVersion;
int microVersion;
char *parsebuf;
int parselen;
};
/**
* Execute the "bzr revno" command and return the result.
* This is a simple, small class.
*/
{
public:
/**
* Safe way. Execute "bzr revno" and return the result.
* Safe from changes in format.
*/
{
if (!ret)
{
return false;
}
return true;
}
};
/**
* Execute the "svn info" command and parse the result.
* This is a simple, small class. Define here, because it
* is used by MakeBase implementation methods.
*/
{
public:
#if 0
/**
* Safe way. Execute "svn info --xml" and parse the result. Search for
* elements/attributes. Safe from changes in format.
*/
{
if (!ret)
{
return false;
}
if (!elem)
{
return false;
}
{
}
return true;
}
#else
/**
* Universal way. Parse the file directly. Not so safe from
* changes in format.
*/
{
if (!f)
{
error("could not open SVN 'entries' file");
return false;
}
const char *fieldNames[] =
{
"format-nbr",
"name",
"kind",
"revision",
"url",
"repos",
"schedule",
"text-time",
"checksum",
"committed-date",
"committed-rev",
"last-author",
"has-props",
"has-prop-mods",
"cachable-props",
};
for (int i=0 ; i<15 ; i++)
{
inbuf[0] = '\0';
break;
}
fclose(f);
return true;
}
private:
#endif
};
/**
* Print a printf()-like formatted error message
*/
{
}
/**
* Print a printf()-like formatted trace message
*/
{
//fprintf(stdout, " ");
}
/**
* Print a printf()-like formatted trace message
*/
{
}
/**
* Resolve another path relative to this one
*/
{
return ret;
}
/**
* Check if a given string matches a given regex pattern
*/
{
bool ret = true;
if (res < 0)
{
ret = false;
// error cases
if (res < -1)
{
switch(res)
{
err = "unexpected quantifier"; break;
case SLRE_UNBALANCED_BRACKETS:
err = "unbalanced brackets"; break;
case SLRE_INTERNAL_ERROR:
err = "internal error"; break;
err = "invald character set"; break;
err = "invalid meta character"; break;
default:
err = "unknown error"; break;
}
}
}
return ret;
}
/**
* 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;
}
/**
* replace 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
{
}
}
return stripped;
}
/**
* remove leading whitespace from each line
*/
{
for (int i = 0 ; i<len ; )
{
char ch;
//Skip to first visible character
while (i<len)
{
ch = s[i];
break;
i++;
}
//Copy the rest of the line
while (i<len)
{
ch = s[i];
{
if (ch != '\r')
i++;
break;
}
else
{
}
i++;
}
}
return out;
}
/**
* Removes whitespace from beginning and end of a string
*/
{
if (s.size() < 1)
return s;
//Find first non-ws char
{
break;
}
//Find first non-ws char, going in reverse
{
break;
}
//trace("begin:%d end:%d", begin, end);
return res;
}
/**
* Return a lower case version of the given string
*/
{
if (s.size()==0)
return s;
{
}
return ret;
}
/**
* Return the native format of the canonical
* path which we store
*/
{
#ifdef __WIN32__
{
if (path[0] == '/' &&
firstChar++;
}
{
if (ch == '/')
else
}
return npath;
#else
return path;
#endif
}
#ifdef __WIN32__
#include <tchar.h>
{
NULL,
dw,
0,
0, NULL );
if(p != NULL)
{ // lose CRLF
*p = _T('\0');
}
return ret;
}
#endif
#ifdef __WIN32__
/**
* Execute a system call, using pipes to send data to the
* program's stdin, and reading stdout and stderr.
*/
{
// status("============ cmd ============\n%s\n=============================",
// command.c_str());
/*
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;
}
//# to see how Win32 pipes work
//# 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;
}
} else {
}
// Create the process
{
error("executeCommand : could not create process : %s",
win32LastError().c_str());
ret = false;
}
delete[] paramBuf;
&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;
}
{
error("executeCommand: could not close read pipe");
return false;
}
bool lastLoop = false;
while (true)
{
//trace("## stderr");
if (avail > 0)
{
bytesRead = 0;
if (bytesRead > 0)
{
for (unsigned int i=0 ; i<bytesRead ; i++)
}
}
//trace("## stdout");
if (avail > 0)
{
bytesRead = 0;
if (bytesRead > 0)
{
for (unsigned int i=0 ; i<bytesRead ; i++)
}
}
//Was this the final check after program done?
if (lastLoop)
break;
if (exitCode != STILL_ACTIVE)
lastLoop = true;
Sleep(10);
}
//trace("outbuf:%s", outbuf.c_str());
if (!CloseHandle(stdoutRead))
{
error("executeCommand: could not close read pipe");
return false;
}
{
error("executeCommand: could not close read pipe");
return false;
}
//trace("exit code:%d", exitCode);
if (exitCode != 0)
{
ret = false;
}
return ret;
}
#else /*do it unix style*/
/**
* Execute a system call, using pipes to send data to the
* program's stdin, and reading stdout and stderr.
*/
{
status("============ cmd ============\n%s\n=============================",
return false;
return false;
if (pid < 0)
{
error("launch of command '%s' failed : %s",
return false;
}
else if (pid > 0) // parent
{
}
else // == 0, child
{
args[0] = (char *)"sh";
}
bool outOpen = true;
bool errOpen = true;
{
char ch;
if (outOpen)
if (errOpen)
if (ret < 0)
break;
{
{ outOpen = false; }
else if (ch <= 0)
{ /* outOpen = false; */ }
else
}
{
{ errOpen = false; }
else if (ch <= 0)
{ /* errOpen = false; */ }
else
}
}
int childReturnValue;
if (childReturnValue != 0)
{
error("exec of command '%s' failed : %s",
return false;
}
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;
}
{
{
}
if (!dir)
{
error("Could not open directory %s : %s",
return false;
}
while (true)
{
if (!de)
break;
//Get the directory member name
if (s.size() == 0 || s[0] == '.')
continue;
{
}
if (isDirectory(fullChild))
{
//trace("directory: %s", childName.c_str());
return false;
continue;
}
else if (!isRegularFile(fullChild))
{
return false;
}
//all done!
}
return true;
}
/**
* Several different classes extend MakeBase. By "propRef", we mean
* the one holding the properties. Likely "Make" itself
*/
{
//before doing the list, resolve any property references
//that might have been specified in the directory name, such as ${src}
return false;
return false;
//If there are <includes>, then add files to the output
//in the order of the include list
else
{
{
{
if (regexMatch(s, pattern))
{
//trace("INCLUDED:%s", s.c_str());
}
}
}
}
//Now trim off the <excludes>
{
bool skipme = false;
{
if (regexMatch(s, pattern))
{
//trace("EXCLUDED:%s", s.c_str());
skipme = true;
break;
}
}
if (!skipme)
}
return true;
}
/**
* 0 == all, 1 = cflags, 2 = libs
*/
int query,
{
return false;
if (query == 0)
else if (query == 1)
else
{
continue;
{
return false;
}
}
return true;
}
{
return false;
return true;
}
/**
* replace a variable ref like ${a} with a value
*/
{
{
if (!envstr)
{
return false;
}
}
{
return false;
}
{
return false;
}
{
return false;
}
{
//SvnInfo svnInfo;
if (varname == "revision")
{
return "";
}
/*if (!svnInfo.query(varname, val))
return false;
result = val;*/
}
else
{
{
}
else
{
return false;
}
}
return true;
}
/**
* Analyse a string, looking for any substitutions or other
* things that need resolution
*/
{
if (depth > 10)
{
error("nesting of substitutions too deep (>10) for '%s'",
return false;
}
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 == '}')
{
return false;
//Now see if the answer has ${} in it, too
return false;
break;
}
else
{
}
}
i = j;
}
else
{
}
}
return true;
}
/**
* Analyse a string, looking for any substitutions or other
* things that need resilution
*/
{
}
/**
* replace variable refs like ${a} with their values
* Assume that the string has already been syntax validated
*/
{
if (s.size()==0)
return defaultVal;
if (getSubstitutions(s, ret))
return ret;
else
return defaultVal;
}
/**
* replace variable refs like ${a} with their values
* return true or false
* Assume that the string has already been syntax validated
*/
{
if (s.size()==0)
return defaultVal;
return defaultVal;
return true;
else
return false;
}
{
if (s.size()==0) {
return defaultVal;
}
// perhaps some error checking, but... bah! waste of time
return val;
}
/**
* Get a string attribute, testing it for proper syntax and
* property names.
*/
{
if (ret)
result = s; //assign -if- ok
return ret;
}
/**
* Get a string value, testing it for proper syntax and
* property names.
*/
{
if (ret)
result = s; //assign -if- ok
return ret;
}
/**
* 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;
/*
std::vector<String> fileList;
if (dir.size() > 0)
{
String baseDir = propRef.resolve(dir);
if (!listFiles(baseDir, "", includes, excludes, fileList))
return false;
}
std::sort(fileList.begin(), fileList.end());
result = fileList;
*/
/*
for (std::size_t i=0 ; i<result.size() ; i++)
{
trace("RES:%s", result[i].c_str());
}
*/
return true;
}
/**
* Parse a <filelist> entry. This is far simpler than FileSet,
* since no directory scanning is needed. The file names are listed
* explicitly.
*/
{
//Look for child tags, namely "file"
{
if (tagName == "file")
{
{
return false;
}
}
else
{
return false;
}
}
//Get the base directory for reading file names
return false;
return true;
}
/**
* Create a directory, making intermediate dirs
* if necessary
*/
{
//trace("## createDirectory: %s", dirname.c_str());
//## first check if it exists
#ifdef __WIN32__
return true;
#endif
{
{
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
{
//A letter root (c:) ?
if (!createDirectory(subpath))
return false;
}
//## 3: now make
#ifdef __WIN32__
#else
#endif
{
error("cannot make directory '%s' : %s",
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;
}
}
{
//trace("not regular: %s", cnative);
}
else
{
//trace("DEL file: %s", childName.c_str());
if (!removeFile(childName))
{
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
#ifndef __WIN32__
if (!srcf)
{
return false;
}
if (!destf)
{
return false;
}
{
if (ch<0)
break;
}
#else
{
error("copyFile from %s to %s failed",
return false;
}
#endif /* __WIN32__ */
return true;
}
/**
* Delete a file
*/
{
if (!fileExists(native))
{
return true;
}
#ifdef WIN32
// On Windows 'remove' will only delete files
{
{
}
{
}
else
{
}
return false;
}
#else
if (!isRegularFile(native))
{
return false;
}
{
{
}
else
{
}
return false;
}
#endif
return true;
}
/**
* Tests if the file exists
*/
{
//Exists?
return false;
return true;
}
/**
* Tests if the file exists and is a regular file
*/
{
//Exists?
return false;
//check the file mode
return false;
return true;
}
/**
* Tests if the file exists and is a directory
*/
{
//Exists?
return false;
//check the file mode
return false;
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
//########################################################################
/**
* 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.
* Pkg-config is line-oriented, so check for newline
*/
{
{
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;
}
{
return true;
int pos = 0;
{
break;
//trace("val %s", val.c_str());
}
return true;
}
{
if (ends == s)
return 0L;
else
return val;
}
{
return;
{
}
else
{
pos++;
{
{
}
else
{
pos++;
}
}
}
//trace("version:%d.%d.%d", majorVersion,
// minorVersion, microVersion );
}
{
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("prefix override:%s", prefix.c_str());
}
else
{
//trace("subVal:%s", subVal.c_str());
}
}
else
pos++;
}
if (attrNameL == "name")
else if (attrNameL == "description")
else if (attrNameL == "cflags")
else if (attrNameL == "libs")
else if (attrNameL == "requires")
else if (attrNameL == "version")
//trace("name:'%s' value:'%s'",
// attrName.c_str(), attrVal.c_str());
}
return true;
}
{
init();
int lineNr = 0;
{
{
return false;
lineNr++;
}
else
{
}
}
{
return false;
}
parseVersion();
return true;
}
{
//trace("### PkgConfig attributes for %s", fileName.c_str());
{
}
}
{
if (!f)
{
return false;
}
while (true)
{
if (ch < 0)
break;
}
fclose(f);
//trace("####### File:\n%s", buf.c_str());
{
return false;
}
//dumpAttrs();
return true;
}
{
{
error("Cannot find package '%s'. Do you have it installed?",
return false;
}
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
*/
{ 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
*/
bool forceRefresh);
/**
* Save a dependency file
*/
private:
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
*
*/
/**
* A list of all files which will be processed for
* dependencies.
*/
/**
* 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 output file list
//allFiles actually contains the master copies. delete them
}
/**
* 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.
*/
{
{
//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.
*/
{
//# if the name is an exact match to a path name
//# in allFiles, like "myinc.h"
{
//h file in same dir
//trace("local: '%s'", iname.c_str());
return true;
}
else
{
//## Ok, it was not found directly
//look in other dirs
{
if (fullPath[0] == '/')
//trace("Normalized %s to %s", dfname.c_str(), fullPath.c_str());
{
//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 (!feof(f))
{
}
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.
*/
{
{
{
//trace("file '%s' already seen", fname.c_str());
continue;
}
}
return true;
}
/**
* Generate the file dependency list.
*/
{
//# First pass. Scan for all includes
{
{
//quit?
}
}
//# Second pass. Scan for all includes
{
{
//String cFileName = iter->first;
//add the .c file first? no, don't
//ofile->files[cFileName] = include;
//trace("ofile:%s", fname.c_str());
processDependency(ofile, include);
}
}
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)
{
//error("Could not open %s for reading", depFile.c_str());
return result;
}
{
error("loadDepFile: main xml element should be <dependencies>");
delete root;
return result;
}
//########## Start parsing
{
if (tagName != "object")
{
error("loadDepFile: <dependencies> should have only <object> children");
return result;
}
//trace("object:%s", objName.c_str());
//########## DESCRIPTION
{
if (tagName != "dep")
{
error("loadDepFile: <object> should have only <dep> children");
return result;
}
//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.
*/
bool forceRefresh)
{
if (forceRefresh)
{
}
else
{
//try once
{
//fail? try again
}
}
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";
}
{
}
/**
* Show task status
*/
{
}
{
return str;
}
int type;
};
/**
* 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:
{
name = "cc";
}
virtual ~TaskCC()
{}
{
{
return true;
}
return false;
}
virtual bool execute()
{
//evaluate our parameters
return false;
//refreshCache is probably false here, unless specified otherwise
{
taskstatus("regenerating C/C++ dependency cache");
refreshCache = true;
}
{
}
{
}
{
}
{
//check excludeInc to see if we dont want to include this dir
if (isExcludedInc(dirName))
continue;
{
}
}
// First create all directories, fails if done in OpenMP parallel loop below... goes superfast anyway, so don't optimize
{
//## Make paths
{
}
//## Make sure destination directory exists
if (!createDirectory(destPath))
{
if (f) {
fclose(f);
}
return false;
}
}
/**
* Compile each of the C files that need it
*/
bool errorOccurred = false;
#ifdef _OPENMP
#endif
{
//## Select command
{
}
//## Make paths
{
}
//## Check whether it needs to be done
{
}
{
}
bool compileMe = false;
//# First we check if the source is newer than the .o
{
// taskstatus("compile of %s (req. by: %s)",
// destFullName.c_str(), srcFullName.c_str());
compileMe = true;
}
else
{
//# secondly, we check if any of the included dependencies
//# of the .c/.cpp is newer than the .o
{
{
}
//trace("%d %s %s\n", depRequires,
// destFullName.c_str(), depFullName.c_str());
if (depRequires)
{
taskstatus("compile %s (%s modified)",
compileMe = true;
break;
}
}
}
if (!compileMe)
{
continue;
}
//## Assemble the command
//## Execute the command
if (f)
{
fprintf(f, "########################### File : %s\n",
srcFullName.c_str());
fprintf(f, "#### COMMAND ###\n");
int col = 0;
{
{
fputc('\n', f);
col = 0;
}
else
{
col++;
}
if (col > 76)
{
fputc('\n', f);
col = 0;
}
}
fprintf(f, "\n");
fflush(f);
}
if (!ret) {
errorOccurred = true;
}
if (errorOccurred && !continueOnError) {
#ifndef _OPENMP // figure out a way to break the loop here with OpenMP
break;
#endif
}
}
if (f)
{
fclose(f);
}
return !errorOccurred;
}
{
String s;
return false;
if (commandOpt.size()>0)
return false;
return false;
return false;
return false;
return false;
{
if (tagName == "flags")
{
return false;
}
else if (tagName == "cxxflags")
{
return false;
}
else if (tagName == "includes")
{
return false;
}
else if (tagName == "defines")
{
return false;
}
else if (tagName == "fileset")
{
return false;
}
else if (tagName == "excludeinc")
{
return false;
}
}
return true;
}
protected:
};
/**
*
*/
{
public:
typedef enum
{
} CopyType;
{
name = "copy";
haveFileSet = false;
}
virtual ~TaskCopy()
{}
virtual bool execute()
{
switch (cptype)
{
case CP_TOFILE:
{
{
taskstatus("%s to %s",
if (verbose)
if (!isRegularFile(fullSource))
{
return false;
}
{
taskstatus("skipped");
return true;
}
return false;
taskstatus("1 file copied");
}
return true;
}
case CP_TODIR:
{
if (haveFileSet)
{
return false;
taskstatus("%s to %s",
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());
if (verbose)
taskstatus("copy %s to new dir : %s",
{
if (verbose)
continue;
}
return false;
nrFiles++;
}
}
else //file source
{
//For file->dir we want only the basename of
//the source appended to the dest dir
taskstatus("%s to %s",
{
}
if (verbose)
if (!isRegularFile(fullSource))
{
return false;
}
{
taskstatus("skipped");
return true;
}
return false;
taskstatus("1 file copied");
}
return true;
}
}
return true;
}
{
return false;
return false;
if (toFileNameOpt.size() > 0)
return false;
if (toDirNameOpt.size() > 0)
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 haveFileSet;
};
/**
* Generate CxxTest files
*/
{
public:
{
name = "cxxtestpart";
}
virtual ~TaskCxxTestPart()
{}
virtual bool execute()
{
return false;
unsigned int newFiles = 0;
{
continue;
if (fileSetDir.size()>0)
{
}
}
if (newFiles>0) {
if (!createDirectory(directory))
return false;
}
{
return false;
}
}
return true;
}
{
return false;
return false;
{
if (tagName == "fileset")
{
return false;
}
}
return true;
}
private:
};
/**
* Generate the CxxTest root file
*/
{
public:
{
name = "cxxtestroot";
}
virtual ~TaskCxxTestRoot()
{}
virtual bool execute()
{
return false;
unsigned int newFiles = 0;
if (templateFile.size()>0) {
}
{
continue;
if (fileSetDir.size()>0)
{
}
}
if (newFiles>0) {
if (!createDirectory(directory))
return false;
}
{
return false;
}
}
return true;
}
{
return false;
return false;
return false;
{
if (tagName == "fileset")
{
return false;
}
}
return true;
}
private:
};
/**
* Execute the CxxTest test executable
*/
{
public:
{
name = "cxxtestrun";
}
virtual ~TaskCxxTestRun()
{}
virtual bool execute()
{
unsigned int newFiles = 0;
if (fileExists(rawCmd)) {
} else {
}
// Note that the log file names are based on the exact name used to call cxxtests (it uses argv[0] + ".log"/".xml")
// Prepend the necessary ../'s
unsigned int workingDirDepth = 0;
bool wasSlash = true;
// This assumes no . and .. parts
}
for(size_t i=0; i<workingDirDepth; i++) {
}
if (newFiles>0) {
if (workingDir.size()>0) {
// TODO: Double-check usage of getcwd and handle chdir errors
}
{
return false;
}
if (workingDir.size()>0) {
// TODO: Handle errors?
}
}
return true;
}
{
return false;
return false;
return true;
}
private:
};
/**
*
*/
{
public:
typedef enum
{
} DeleteType;
{
type = TASK_DELETE;
name = "delete";
}
virtual ~TaskDelete()
{}
virtual bool execute()
{
switch (delType)
{
case DEL_FILE:
{
{
//error("Could not delete file '%s'", fullName.c_str());
return false;
}
return true;
}
case DEL_DIR:
{
{
//error("Could not delete directory '%s'", fullDir.c_str());
return false;
}
return true;
}
}
return true;
}
{
return false;
if (fileNameOpt.size() > 0)
return false;
if (dirNameOpt.size() > 0)
{
error("<delete> can have one attribute of file= or dir=");
return false;
}
{
error("<delete> must have one attribute of file= or dir=");
return false;
}
return false;
return false;
return false;
return true;
}
private:
int delType;
};
/**
* Send a message to stdout
*/
{
public:
virtual ~TaskEcho()
{}
virtual bool execute()
{
//let message have priority over text
{
}
{
}
return true;
}
{
return false;
return false;
return true;
}
private:
};
/**
*
*/
{
public:
virtual ~TaskJar()
{}
virtual bool execute()
{
if (!ret)
{
error("<jar> command '%s' failed :\n %s",
return false;
}
return true;
}
{
return false;
return false;
return false;
{
error("<jar> required both basedir and destfile attributes to be set");
return false;
}
return true;
}
private:
};
/**
*
*/
{
public:
{
}
virtual ~TaskJavac()
{}
virtual bool execute()
{
{
return false;
}
{
}
int count = 0;
{
continue;
continue;
//trace("fullsrc:%s fulldest:%s", fullSrc.c_str(), fullDest.c_str());
continue;
count++;
}
fclose(f);
if (!count)
{
taskstatus("nothing to do");
return true;
}
if (!ret)
{
error("<javac> command '%s' failed :\n %s",
return false;
}
// TODO:
//removeFromStatCache(getNativePath(........));
return true;
}
{
return false;
return false;
return false;
{
error("<javac> required both srcdir and destdir attributes to be set");
return false;
}
return false;
return true;
}
private:
};
/**
*
*/
{
public:
{
}
virtual ~TaskLink()
{}
}
}
}
}
}
virtual bool execute()
{
return false;
//trace("%d files in %s", fileSet.size(), fileSetDir.c_str());
bool doit = false;
{
if (fileSetDir.size()>0)
{
}
//trace("link: tgt:%s obj:%s", fullTarget.c_str(),
// fullObj.c_str());
doit = true;
}
// trim it down to unique elements, reduce command line size
if (!doit)
{
//trace("link not needed");
return true;
}
//trace("LINK cmd:%s", cmd.c_str());
// std::cout << "DEBUG command = " << cmd << std::endl;
{
return false;
}
if (symFileName.size()>0)
{
{
return false;
}
}
if (doStrip)
{
cmd = stripCommand;
{
return false;
}
}
return true;
}
{
return false;
return false;
return false;
return false;
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 file
*/
{
public:
virtual ~TaskMakeFile()
{}
virtual bool execute()
{
{
taskstatus("skipped");
return true;
}
//trace("fullName:%s", fullName.c_str());
if (!f)
{
error("<makefile> could not open %s for writing : %s",
return false;
}
fputc('\n', f);
fclose(f);
return true;
}
{
return false;
return false;
if (fileNameOpt.size() == 0)
{
error("<makefile> requires 'file=\"filename\"' attribute");
return false;
}
return false;
//trace("dirname:%s", dirName.c_str());
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;
if (dirNameOpt.size() == 0)
{
error("<mkdir> requires 'dir=\"dirname\"' attribute");
return false;
}
return true;
}
private:
};
/**
* Create a named directory
*/
{
public:
virtual ~TaskMsgFmt()
{}
virtual bool execute()
{
return false;
//trace("msgfmt: %d", fileSet.size());
{
continue;
if (fileSetDir.size()>0)
{
}
{
}
if (owndir)
{
}
//Pick the output file name
{
}
else
{
}
{
//trace("skip %s", fullSource.c_str());
continue;
}
if (pos>0)
{
if (!createDirectory(fullDestPath))
return false;
}
{
return false;
}
}
return true;
}
{
return false;
return false;
return false;
return false;
{
if (tagName == "fileset")
{
return false;
}
}
return true;
}
private:
};
/**
* Perform a Package-Config query similar to pkg-config
*/
{
public:
typedef enum
{
} QueryTypes;
{
name = "pkg-config";
}
virtual ~TaskPkgConfig()
{}
virtual bool execute()
{
{
return false;
}
if (query == "cflags")
else if (query == "libs")
else if (query == "all")
else
{
return false;
}
return true;
}
{
//# NAME
return false;
if (pkgNameOpt.size()==0)
{
error("<pkg-config> requires 'name=\"package\"' attribute");
return false;
}
//# PROPERTY
return false;
if (propNameOpt.size()==0)
{
error("<pkg-config> requires 'property=\"name\"' attribute");
return false;
}
//# PATH
return false;
//# PREFIX
return false;
//# QUERY
return false;
return true;
}
private:
};
/**
* Process an archive to allow random access
*/
{
public:
virtual ~TaskRanlib()
{}
virtual bool execute()
{
//trace("fullDir:%s", fullDir.c_str());
return false;
// TODO:
//removeFromStatCache(getNativePath(fullDest));
return true;
}
{
return false;
return false;
if (fileNameOpt.size() == 0)
{
error("<ranlib> requires 'file=\"fileNname\"' attribute");
return false;
}
return true;
}
private:
};
/**
* Compile a resource file into a binary object
*/
{
public:
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:
};
/**
* Collect .o's into a .so or DLL
*/
{
public:
virtual ~TaskSharedLib()
{}
virtual bool execute()
{
//trace("###########HERE %d", fileSet.size());
bool doit = false;
//trace("ar fullout: %s", fullOut.c_str());
return false;
{
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 (defFileName.size()>0)
{
}
if (impFileName.size()>0)
{
}
{
if (fileSetDir.size()>0)
{
}
}
{
return false;
}
return true;
}
{
return false;
return false;
return false;
return false;
{
if (tagName == "fileset")
{
return false;
}
else if (tagName == "libs")
{
return false;
}
}
return true;
}
private:
};
/**
* Run the "ar" command to archive .o's into a .a
*/
{
public:
virtual ~TaskStaticLib()
{}
virtual bool execute()
{
bool doit = false;
//trace("ar fullout: %s", fullOut.c_str());
return false;
//trace("###########HERE %s", fileSetDir.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;
return false;
{
if (tagName == "fileset")
{
return false;
}
}
return true;
}
private:
};
/**
* Strip an executable
*/
{
public:
virtual ~TaskStrip()
{}
virtual bool execute()
{
//trace("fullDir:%s", fullDir.c_str());
if (symFileName.size()>0)
{
cmd = "objcopy --only-keep-debug ";
{
return false;
}
}
{
return false;
}
return true;
}
{
return false;
return false;
return false;
if (fileNameOpt.size() == 0)
{
error("<strip> requires 'file=\"fileName\"' attribute");
return false;
}
return true;
}
private:
};
/**
*
*/
{
public:
virtual ~TaskTouch()
{}
virtual bool execute()
{
{
// S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
if (ret != 0)
{
error("<touch> could not create '%s' : %s",
return false;
}
return true;
}
if (ret != 0)
{
error("<touch> could not update the modification time for '%s' : %s",
return false;
}
return true;
}
{
//trace("touch parse");
return false;
if (fileNameOpt.size() == 0)
{
error("<touch> requires 'file=\"fileName\"' attribute");
return false;
}
return true;
}
};
/**
*
*/
{
public:
virtual ~TaskTstamp()
{}
virtual bool execute()
{
return true;
}
{
//trace("tstamp parse");
return true;
}
};
/**
*
*/
{
//trace("task:%s", tagName.c_str());
if (tagName == "cc")
else if (tagName == "copy")
else if (tagName == "cxxtestpart")
else if (tagName == "cxxtestroot")
else if (tagName == "cxxtestrun")
else if (tagName == "delete")
else if (tagName == "echo")
else if (tagName == "jar")
else if (tagName == "javac")
else if (tagName == "link")
else if (tagName == "makefile")
else if (tagName == "mkdir")
else if (tagName == "msgfmt")
else if (tagName == "pkg-config")
else if (tagName == "ranlib")
else if (tagName == "rc")
else if (tagName == "sharedlib")
else if (tagName == "staticlib")
else if (tagName == "strip")
else if (tagName == "touch")
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; }
/**
*
*/
/**
*
*/
{ 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; }
/**
*
*/
{ return BUILDTOOL_VERSION; }
/**
* Overload a <property>
*/
/**
*
*/
virtual 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 = "";
envPrefix = "env.";
pcPrefix = "pc.";
pccPrefix = "pcc.";
pclPrefix = "pcl.";
bzrPrefix = "bzr.";
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))
{
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",
fclose(f);
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;
//allow property to be set, even if val=""
//See if we wanted to overload this property
{
status("overloading property '%s' = '%s'",
}
}
fclose(f);
return true;
}
/**
*
*/
{
{
if (attrName == "name")
{
return false;
{
}
else
{
return false;
//let the property exist, even if not defined
}
//See if we wanted to overload this property
{
status("overloading property '%s' = '%s'",
}
}
else if (attrName == "file")
{
return false;
{
}
return false;
}
else if (attrName == "environment")
{
{
error("environment prefix cannot have a '.' in it");
return false;
}
}
else if (attrName == "pkg-config")
{
{
error("pkg-config prefix cannot have a '.' in it");
return false;
}
}
else if (attrName == "pkg-config-cflags")
{
{
error("pkg-config-cflags prefix cannot have a '.' in it");
return false;
}
}
else if (attrName == "pkg-config-libs")
{
{
error("pkg-config-libs prefix cannot have a '.' in it");
return false;
}
}
else if (attrName == "subversion")
{
{
error("bzr prefix cannot have a '.' in it");
return false;
}
}
}
return true;
}
/**
*
*/
{
setLine(0);
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
}
//######### none of the above
else
{
return false;
}
}
{
{
return false;
}
}
delete root;
status("######## PARSE COMPLETE");
return true;
}
/**
* Overload a <property>
*/
{
{
return false;
}
return true;
}
/**
*
*/
{
if (!parseFile())
return false;
if (!execute())
return false;
return true;
}
/**
* Get a formatted MM:SS.sss time elapsed string
*/
static String
{
{
microsX += 1000000;
secondsX -= 1;
}
return ret;
}
/**
*
*/
{
status("####################################################");
status("####################################################");
if (!run())
return false;
status("####################################################");
status("####################################################");
return true;
}
}// namespace buildtool
//########################################################################
//# M A I N
//########################################################################
/**
* Format an error message in printf() style
*/
{
}
{
int i;
for (i=0 ; i<len ; i++)
{
char ch = s[i];
if (ch == '=')
break;
}
if (i>=len || s[i]!='=')
{
error("property requires -Dname=value");
return false;
}
i++;
for ( ; i<len ; i++)
{
char ch = s[i];
}
return true;
}
/**
* Compare a buffer with a key, for the length of the key
*/
{
{
return false;
}
return true;
}
{
printf("usage:\n");
printf("Options:\n");
printf(" -help, -h print this message\n");
printf(" -version print the version information and exit\n");
printf(" -file <file> use given buildfile\n");
printf(" -f <file> ''\n");
printf(" -D<property>=<value> use value for given property\n");
printf(" -j [N] build using N threads or infinite number of threads if no argument\n");
}
/**
* 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++)
{
{
{
return true;
}
else if (arg == "-version")
{
return true;
}
{
if (i>=argc-1)
{
return false;
}
i++; //eat option
}
else if (arg == "-j")
{
} else {
i++; //eat option
} else {
}
}
}
{
{
return false;
}
return false;
}
else
{
return false;
}
}
else
{
{
error("only one initial target");
return false;
}
}
}
//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::FileRec> 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
//########################################################################