buildtool.cpp revision 735916b6287db8b18564df0d00f5042f26418ad7
/**
* 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
*
*/
#define BUILDTOOL_VERSION "BuildTool v0.9.9multi"
#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__
#include <windows.h>
#endif
#include <errno.h>
//########################################################################
//# Definition of gettimeofday() for those who don't have it
//########################################################################
#ifdef NEED_GETTIMEOFDAY
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of dst correction */
};
{
if (!tv)
return (-1);
if (tz)
{
}
return 0;
}
#endif
namespace buildtool
{
//########################################################################
//########################################################################
//## R E G E X P
//########################################################################
//########################################################################
/**
* This is the T-Rex regular expression library, which we
* gratefully acknowledge. It's clean code and small size allow
* us to embed it in BuildTool without adding a dependency
*
*/
//begin trex.h
#ifndef _TREX_H_
#define _TREX_H_
/***************************************************************
T-Rex a tiny regular expression library
Copyright (C) 2003-2006 Alberto Demichelis
This software is provided 'as-is', without any express
or implied warranty. In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for
any purpose, including commercial applications, and to alter
it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
****************************************************************/
#ifdef _UNICODE
#define TRexChar unsigned short
#define MAX_CHAR 0xFFFF
#define _TREXC(c) L##c
#define trex_strlen wcslen
#define trex_printf wprintf
#else
#define TRexChar char
#define MAX_CHAR 0xFF
#define _TREXC(c) (c)
#define trex_strlen strlen
#define trex_printf printf
#endif
#ifndef TREX_API
#define TREX_API extern
#endif
#define TRex_True 1
#define TRex_False 0
typedef unsigned int TRexBool;
typedef struct {
int len;
} TRexMatch;
TREX_API TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end);
#endif
//end trex.h
//start trex.c
#include <stdio.h>
#include <string>
/* see copyright notice in trex.h */
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <setjmp.h>
//#include "trex.h"
#ifdef _UNICODE
#define _SC(x) L(x)
#else
#define _SC(x) (x)
#endif
#ifdef _DEBUG
#include <stdio.h>
{
};
#endif
#define TREX_SYMBOL_ANY_CHAR ('.')
#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
#define TREX_SYMBOL_BRANCH ('|')
#define TREX_SYMBOL_END_OF_STRING ('$')
#define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
#define TREX_SYMBOL_ESCAPE_CHAR ('\\')
typedef int TRexNodeType;
typedef struct tagTRexNode{
int left;
int right;
int next;
}TRexNode;
struct TRex{
int _first;
int _op;
int _nallocated;
int _nsize;
int _nsubexpr;
int _currsubexp;
void *_jmpbuf;
};
{
TRexNode n;
int newid;
//int oldsize = exp->_nallocated;
}
return (int)newid;
}
{
}
}
{
}
}
{
return n;
}
{
TRexChar t;
case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
case 'p': case 'P': case 'l': case 'u':
{
return trex_charclass(exp,t);
}
case 'b':
case 'B':
if(!isclass) {
return node;
} //else default
default:
return trex_newnode(exp,t);
}
}
}
return trex_newnode(exp,t);
}
{
int ret = -1;
int r,t;
if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
t = trex_escapechar(exp);
chain = r;
first = -1;
}
else{
if(first!=-1){
int c = first;
chain = c;
}
else{
}
}
}
if(first!=-1){
int c = first;
chain = c;
first = -1;
}
/* hack? */
return ret;
}
{
int positions = 10;
positions *= 10;
};
return ret;
}
{
int ret = -1;
{
case '(': {
}
else
}
break;
case '[':
break;
default:
break;
}
{
int op;
case '{':
/*******************************/
case '}':
break;
case ',':
p1 = 0xFFFF;
}
break;
default:
}
/*******************************/
break;
}
if(isgreedy) {
}
}
if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {
}
return ret;
}
{
int ret=-1,e;
}
e = trex_element(exp);
if(ret != -1) {
}
else ret = e;
}
return ret;
}
{
switch(cclass) {
}
return TRex_False; /*cannot happen*/
}
{
do {
case OP_RANGE:
break;
case OP_CCLASS:
break;
default:
}
return TRex_False;
}
{
switch(type) {
case OP_GREEDY: {
//TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
}
else {
greedystop = next;
}
break;
nmaches++;
good=s;
if(greedystop) {
//checks that 0 matches satisfy the expression(if so skips)
//if not would always stop(for instance if is a '?')
{
}
if(stop) {
//if satisfied stop it
}
}
}
break;
}
return NULL;
}
case OP_OR: {
else
return asd;
}
else
return asd;
}
return NULL;
break;
}
case OP_EXPR:
case OP_NOCAPEXPR:{
int capture = -1;
exp->_currsubexp++;
}
do {
if(n->next != -1) {
}else {
}
if(capture != -1){
}
return NULL;
}
if(capture != -1)
return cur;
}
case OP_WB:
}
case OP_BOL:
return NULL;
case OP_EOL:
return NULL;
case OP_DOT:{
*str++;
}
return str;
case OP_NCLASS:
case OP_CLASS:
if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
*str++;
return str;
}
return NULL;
case OP_CCLASS:
*str++;
return str;
}
return NULL;
default: /* char */
*str++;
return str;
}
return NULL;
}
/* public api */
{
#ifdef _DEBUG
{
int nsize,i;
TRexNode *t;
for(i = 0;i < nsize; i++) {
else
scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
}
}
#endif
}
else{
return NULL;
}
return exp;
}
{
if(exp) {
}
}
{
exp->_currsubexp = 0;
return TRex_False;
return TRex_True;
}
TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
{
do {
cur = text_begin;
while(node != -1) {
exp->_currsubexp = 0;
if(!cur)
break;
}
*text_begin++;
return TRex_False;
--text_begin;
return TRex_True;
}
TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
{
}
{
}
{
return TRex_True;
}
//########################################################################
//########################################################################
//## 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; }
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()
{
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;
}
{
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
{
const 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;
}
{
int count = 0;
{
count++;
}
return count;
}
{
int line = 1;
int col = 1;
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;
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;
}
{
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;
};
static statCacheType statCache;
//printf("Stat path: %s\n", f.c_str());
std::pair<statCacheType::iterator, bool> result = statCache.insert(statCacheType::value_type(f, StatResult()));
}
}
static void removeFromStatCache(const String f) {
//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()
{}
/**
*
*/
String getDirectory() const
{ return directory; }
/**
*
*/
/**
*
*/
/**
*
*/
{ return files; }
/**
*
*/
/**
*
*/
{ return includes; }
/**
*
*/
/**
*
*/
{ return excludes; }
/**
*
*/
unsigned int size() const
/**
*
*/
/**
*
*/
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; }
/**
*
*/
unsigned int size()
/**
*
*/
/**
*
*/
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
*/
void setNumThreads(const int num)
{ 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
*/
/**
*
*/
virtual String getDescription()
{ return description; }
/**
*
*/
{ return cflags; }
/**
*
*/
{ return libs; }
/**
*
*/
{
return ret;
}
/**
*
*/
virtual String getVersion()
{ 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:
char inbuf[256];
#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
*/
{
if (!expr)
{
if (!terror)
terror = "undefined";
return false;
}
bool ret = true;
{
ret = true;
}
else
{
ret = false;
}
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
unsigned int begin = 0;
{
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;
for(unsigned int i=0; i<s.size() ; i++)
{
}
return ret;
}
/**
* 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
#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)
{
char readBuf[4096];
//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=============================",
int outfds[2];
return false;
int errfds[2];
return false;
if (pid < 0)
{
error("launch of command '%s' failed : %s",
return false;
}
else if (pid > 0) // parent
{
}
else // == 0, child
{
char *args[4];
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 (unsigned int 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;
}
bool PkgConfig::parseRequires()
{
return true;
int pos = 0;
{
break;
//trace("val %s", val.c_str());
}
return true;
}
{
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 );
}
{
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
*/
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
*/
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;
static const int readBufSize = 8192;
};
/**
* 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.
*/
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.
*/
{
//# 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.
*/
bool DepTool::generateDependencies()
{
//# 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
*/
void taskstatus(const char *fmt, ...)
{
}
{
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()
{}
{
for (unsigned int i=0 ; i<excludeInc.size() ; i++)
{
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 == "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
*/
class TaskCxxTestPart: public Task
{
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
*/
class TaskCxxTestRoot: public Task
{
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
*/
class TaskCxxTestRun: public Task
{
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) {
char olddir[1024];
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:
};
/**
*
*/
class TaskDelete : public Task
{
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());
{
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
*/
class TaskMakeFile : public Task
{
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
*/
class TaskMsgFmt: public Task
{
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
*/
class TaskPkgConfig : public Task
{
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
*/
class TaskRanlib : public Task
{
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
*/
class TaskSharedLib : public Task
{
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
*/
class TaskStaticLib : public Task
{
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;
}
};
/**
*
*/
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 == "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; }
/**
*
*/
/**
*
*/
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; }
/**
*
*/
{ 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))
{
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",
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;
}
char buf[80];
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
//########################################################################