diff --git a/buildtool.cpp b/buildtool.cpp
index e3efeff5eb4270a3714547768f3069825a85b30a..e2c28b4c0e56204bb76f5b3c976637ab44a8e881 100644 (file)
--- a/buildtool.cpp
+++ b/buildtool.cpp
* Authors:
* Bob Jamison
*
- * Copyright (C) 2006 Bob Jamison
+ * Copyright (C) 2006-2007 Bob Jamison
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
/**
* To use this file, compile with:
* <pre>
- * g++ -O3 buildtool.cpp -o build.exe
+ * g++ -O3 buildtool.cpp -o btool.exe
* (or whatever your compiler might be)
* Then
- * build
+ * btool
* or
- * build {target}
+ * btool {target}
*/
#endif
+#include <errno.h>
+
+
+//########################################################################
+//# Definition of gettimeofday() for those who don't have it
+//########################################################################
+#ifdef __WIN32__
+#include <sys/timeb.h>
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+ };
+
+static int gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+ struct _timeb tb;
+
+ if (!tv)
+ return (-1);
+
+ _ftime (&tb);
+ tv->tv_sec = tb.time;
+ tv->tv_usec = tb.millitm * 1000 + 500;
+ if (tz)
+ {
+ tz->tz_minuteswest = -60 * _timezone;
+ tz->tz_dsttime = _daylight;
+ }
+ 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 TRex TRex;
+
+typedef struct {
+ const TRexChar *begin;
+ int len;
+} TRexMatch;
+
+TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error);
+TREX_API void trex_free(TRex *exp);
+TREX_API TRexBool trex_match(TRex* exp,const TRexChar* text);
+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);
+TREX_API int trex_getsubexpcount(TRex* exp);
+TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
+
+#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 _UINCODE
+#define scisprint iswprint
+#define scstrlen wcslen
+#define scprintf wprintf
+#define _SC(x) L(x)
+#else
+#define scisprint isprint
+#define scstrlen strlen
+#define scprintf printf
+#define _SC(x) (x)
+#endif
+
+#ifdef _DEBUG
+#include <stdio.h>
+
+static const TRexChar *g_nnames[] =
+{
+ _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
+ _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
+ _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
+ _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
+};
+
+#endif
+#define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
+#define OP_OR (MAX_CHAR+2)
+#define OP_EXPR (MAX_CHAR+3) //parentesis ()
+#define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
+#define OP_DOT (MAX_CHAR+5)
+#define OP_CLASS (MAX_CHAR+6)
+#define OP_CCLASS (MAX_CHAR+7)
+#define OP_NCLASS (MAX_CHAR+8) //negates class the [^
+#define OP_RANGE (MAX_CHAR+9)
+#define OP_CHAR (MAX_CHAR+10)
+#define OP_EOL (MAX_CHAR+11)
+#define OP_BOL (MAX_CHAR+12)
+#define OP_WB (MAX_CHAR+13)
+
+#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{
+ TRexNodeType type;
+ int left;
+ int right;
+ int next;
+}TRexNode;
+
+struct TRex{
+ const TRexChar *_eol;
+ const TRexChar *_bol;
+ const TRexChar *_p;
+ int _first;
+ int _op;
+ TRexNode *_nodes;
+ int _nallocated;
+ int _nsize;
+ int _nsubexpr;
+ TRexMatch *_matches;
+ int _currsubexp;
+ void *_jmpbuf;
+ const TRexChar **_error;
+};
+
+static int trex_list(TRex *exp);
+
+static int trex_newnode(TRex *exp, TRexNodeType type)
+{
+ TRexNode n;
+ int newid;
+ n.type = type;
+ n.next = n.right = n.left = -1;
+ if(type == OP_EXPR)
+ n.right = exp->_nsubexpr++;
+ if(exp->_nallocated < (exp->_nsize + 1)) {
+ //int oldsize = exp->_nallocated;
+ exp->_nallocated *= 2;
+ exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
+ }
+ exp->_nodes[exp->_nsize++] = n;
+ newid = exp->_nsize - 1;
+ return (int)newid;
+}
+
+static void trex_error(TRex *exp,const TRexChar *error)
+{
+ if(exp->_error) *exp->_error = error;
+ longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
+}
+
+static void trex_expect(TRex *exp, int n){
+ if((*exp->_p) != n)
+ trex_error(exp, _SC("expected paren"));
+ exp->_p++;
+}
+
+static TRexChar trex_escapechar(TRex *exp)
+{
+ if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
+ exp->_p++;
+ switch(*exp->_p) {
+ case 'v': exp->_p++; return '\v';
+ case 'n': exp->_p++; return '\n';
+ case 't': exp->_p++; return '\t';
+ case 'r': exp->_p++; return '\r';
+ case 'f': exp->_p++; return '\f';
+ default: return (*exp->_p++);
+ }
+ } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));
+ return (*exp->_p++);
+}
+
+static int trex_charclass(TRex *exp,int classid)
+{
+ int n = trex_newnode(exp,OP_CCLASS);
+ exp->_nodes[n].left = classid;
+ return n;
+}
+
+static int trex_charnode(TRex *exp,TRexBool isclass)
+{
+ TRexChar t;
+ if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
+ exp->_p++;
+ switch(*exp->_p) {
+ case 'n': exp->_p++; return trex_newnode(exp,'\n');
+ case 't': exp->_p++; return trex_newnode(exp,'\t');
+ case 'r': exp->_p++; return trex_newnode(exp,'\r');
+ case 'f': exp->_p++; return trex_newnode(exp,'\f');
+ case 'v': exp->_p++; return trex_newnode(exp,'\v');
+ 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':
+ {
+ t = *exp->_p; exp->_p++;
+ return trex_charclass(exp,t);
+ }
+ case 'b':
+ case 'B':
+ if(!isclass) {
+ int node = trex_newnode(exp,OP_WB);
+ exp->_nodes[node].left = *exp->_p;
+ exp->_p++;
+ return node;
+ } //else default
+ default:
+ t = *exp->_p; exp->_p++;
+ return trex_newnode(exp,t);
+ }
+ }
+ else if(!scisprint(*exp->_p)) {
+
+ trex_error(exp,_SC("letter expected"));
+ }
+ t = *exp->_p; exp->_p++;
+ return trex_newnode(exp,t);
+}
+static int trex_class(TRex *exp)
+{
+ int ret = -1;
+ int first = -1,chain;
+ if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
+ ret = trex_newnode(exp,OP_NCLASS);
+ exp->_p++;
+ }else ret = trex_newnode(exp,OP_CLASS);
+
+ if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
+ chain = ret;
+ while(*exp->_p != ']' && exp->_p != exp->_eol) {
+ if(*exp->_p == '-' && first != -1){
+ int r,t;
+ if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
+ r = trex_newnode(exp,OP_RANGE);
+ if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
+ if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
+ exp->_nodes[r].left = exp->_nodes[first].type;
+ t = trex_escapechar(exp);
+ exp->_nodes[r].right = t;
+ exp->_nodes[chain].next = r;
+ chain = r;
+ first = -1;
+ }
+ else{
+ if(first!=-1){
+ int c = first;
+ exp->_nodes[chain].next = c;
+ chain = c;
+ first = trex_charnode(exp,TRex_True);
+ }
+ else{
+ first = trex_charnode(exp,TRex_True);
+ }
+ }
+ }
+ if(first!=-1){
+ int c = first;
+ exp->_nodes[chain].next = c;
+ chain = c;
+ first = -1;
+ }
+ /* hack? */
+ exp->_nodes[ret].left = exp->_nodes[ret].next;
+ exp->_nodes[ret].next = -1;
+ return ret;
+}
+
+static int trex_parsenumber(TRex *exp)
+{
+ int ret = *exp->_p-'0';
+ int positions = 10;
+ exp->_p++;
+ while(isdigit(*exp->_p)) {
+ ret = ret*10+(*exp->_p++-'0');
+ if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
+ positions *= 10;
+ };
+ return ret;
+}
+
+static int trex_element(TRex *exp)
+{
+ int ret = -1;
+ switch(*exp->_p)
+ {
+ case '(': {
+ int expr,newn;
+ exp->_p++;
+
+
+ if(*exp->_p =='?') {
+ exp->_p++;
+ trex_expect(exp,':');
+ expr = trex_newnode(exp,OP_NOCAPEXPR);
+ }
+ else
+ expr = trex_newnode(exp,OP_EXPR);
+ newn = trex_list(exp);
+ exp->_nodes[expr].left = newn;
+ ret = expr;
+ trex_expect(exp,')');
+ }
+ break;
+ case '[':
+ exp->_p++;
+ ret = trex_class(exp);
+ trex_expect(exp,']');
+ break;
+ case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
+ case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
+ default:
+ ret = trex_charnode(exp,TRex_False);
+ break;
+ }
+
+ {
+ int op;
+ TRexBool isgreedy = TRex_False;
+ unsigned short p0 = 0, p1 = 0;
+ switch(*exp->_p){
+ case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
+ case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
+ case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
+ case '{':
+ exp->_p++;
+ if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
+ p0 = (unsigned short)trex_parsenumber(exp);
+ /*******************************/
+ switch(*exp->_p) {
+ case '}':
+ p1 = p0; exp->_p++;
+ break;
+ case ',':
+ exp->_p++;
+ p1 = 0xFFFF;
+ if(isdigit(*exp->_p)){
+ p1 = (unsigned short)trex_parsenumber(exp);
+ }
+ trex_expect(exp,'}');
+ break;
+ default:
+ trex_error(exp,_SC(", or } expected"));
+ }
+ /*******************************/
+ isgreedy = TRex_True;
+ break;
+
+ }
+ if(isgreedy) {
+ int nnode = trex_newnode(exp,OP_GREEDY);
+ op = OP_GREEDY;
+ exp->_nodes[nnode].left = ret;
+ exp->_nodes[nnode].right = ((p0)<<16)|p1;
+ ret = nnode;
+ }
+ }
+ 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')) {
+ int nnode = trex_element(exp);
+ exp->_nodes[ret].next = nnode;
+ }
+
+ return ret;
+}
+
+static int trex_list(TRex *exp)
+{
+ int ret=-1,e;
+ if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
+ exp->_p++;
+ ret = trex_newnode(exp,OP_BOL);
+ }
+ e = trex_element(exp);
+ if(ret != -1) {
+ exp->_nodes[ret].next = e;
+ }
+ else ret = e;
+
+ if(*exp->_p == TREX_SYMBOL_BRANCH) {
+ int temp,tright;
+ exp->_p++;
+ temp = trex_newnode(exp,OP_OR);
+ exp->_nodes[temp].left = ret;
+ tright = trex_list(exp);
+ exp->_nodes[temp].right = tright;
+ ret = temp;
+ }
+ return ret;
+}
+
+static TRexBool trex_matchcclass(int cclass,TRexChar c)
+{
+ switch(cclass) {
+ case 'a': return isalpha(c)?TRex_True:TRex_False;
+ case 'A': return !isalpha(c)?TRex_True:TRex_False;
+ case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
+ case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
+ case 's': return isspace(c)?TRex_True:TRex_False;
+ case 'S': return !isspace(c)?TRex_True:TRex_False;
+ case 'd': return isdigit(c)?TRex_True:TRex_False;
+ case 'D': return !isdigit(c)?TRex_True:TRex_False;
+ case 'x': return isxdigit(c)?TRex_True:TRex_False;
+ case 'X': return !isxdigit(c)?TRex_True:TRex_False;
+ case 'c': return iscntrl(c)?TRex_True:TRex_False;
+ case 'C': return !iscntrl(c)?TRex_True:TRex_False;
+ case 'p': return ispunct(c)?TRex_True:TRex_False;
+ case 'P': return !ispunct(c)?TRex_True:TRex_False;
+ case 'l': return islower(c)?TRex_True:TRex_False;
+ case 'u': return isupper(c)?TRex_True:TRex_False;
+ }
+ return TRex_False; /*cannot happen*/
+}
+
+static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
+{
+ do {
+ switch(node->type) {
+ case OP_RANGE:
+ if(c >= node->left && c <= node->right) return TRex_True;
+ break;
+ case OP_CCLASS:
+ if(trex_matchcclass(node->left,c)) return TRex_True;
+ break;
+ default:
+ if(c == node->type)return TRex_True;
+ }
+ } while((node->next != -1) && (node = &exp->_nodes[node->next]));
+ return TRex_False;
+}
+
+static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
+{
+
+ TRexNodeType type = node->type;
+ switch(type) {
+ case OP_GREEDY: {
+ //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
+ TRexNode *greedystop = NULL;
+ int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
+ const TRexChar *s=str, *good = str;
+
+ if(node->next != -1) {
+ greedystop = &exp->_nodes[node->next];
+ }
+ else {
+ greedystop = next;
+ }
+
+ while((nmaches == 0xFFFF || nmaches < p1)) {
+
+ const TRexChar *stop;
+ if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
+ 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(greedystop->type != OP_GREEDY ||
+ (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
+ {
+ TRexNode *gnext = NULL;
+ if(greedystop->next != -1) {
+ gnext = &exp->_nodes[greedystop->next];
+ }else if(next && next->next != -1){
+ gnext = &exp->_nodes[next->next];
+ }
+ stop = trex_matchnode(exp,greedystop,s,gnext);
+ if(stop) {
+ //if satisfied stop it
+ if(p0 == p1 && p0 == nmaches) break;
+ else if(nmaches >= p0 && p1 == 0xFFFF) break;
+ else if(nmaches >= p0 && nmaches <= p1) break;
+ }
+ }
+ }
+
+ if(s >= exp->_eol)
+ break;
+ }
+ if(p0 == p1 && p0 == nmaches) return good;
+ else if(nmaches >= p0 && p1 == 0xFFFF) return good;
+ else if(nmaches >= p0 && nmaches <= p1) return good;
+ return NULL;
+ }
+ case OP_OR: {
+ const TRexChar *asd = str;
+ TRexNode *temp=&exp->_nodes[node->left];
+ while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
+ if(temp->next != -1)
+ temp = &exp->_nodes[temp->next];
+ else
+ return asd;
+ }
+ asd = str;
+ temp = &exp->_nodes[node->right];
+ while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
+ if(temp->next != -1)
+ temp = &exp->_nodes[temp->next];
+ else
+ return asd;
+ }
+ return NULL;
+ break;
+ }
+ case OP_EXPR:
+ case OP_NOCAPEXPR:{
+ TRexNode *n = &exp->_nodes[node->left];
+ const TRexChar *cur = str;
+ int capture = -1;
+ if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
+ capture = exp->_currsubexp;
+ exp->_matches[capture].begin = cur;
+ exp->_currsubexp++;
+ }
+
+ do {
+ TRexNode *subnext = NULL;
+ if(n->next != -1) {
+ subnext = &exp->_nodes[n->next];
+ }else {
+ subnext = next;
+ }
+ if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
+ if(capture != -1){
+ exp->_matches[capture].begin = 0;
+ exp->_matches[capture].len = 0;
+ }
+ return NULL;
+ }
+ } while((n->next != -1) && (n = &exp->_nodes[n->next]));
+
+ if(capture != -1)
+ exp->_matches[capture].len = cur - exp->_matches[capture].begin;
+ return cur;
+ }
+ case OP_WB:
+ if(str == exp->_bol && !isspace(*str)
+ || (str == exp->_eol && !isspace(*(str-1)))
+ || (!isspace(*str) && isspace(*(str+1)))
+ || (isspace(*str) && !isspace(*(str+1))) ) {
+ return (node->left == 'b')?str:NULL;
+ }
+ return (node->left == 'b')?NULL:str;
+ case OP_BOL:
+ if(str == exp->_bol) return str;
+ return NULL;
+ case OP_EOL:
+ if(str == exp->_eol) return str;
+ 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:
+ if(trex_matchcclass(node->left,*str)) {
+ *str++;
+ return str;
+ }
+ return NULL;
+ default: /* char */
+ if(*str != node->type) return NULL;
+ *str++;
+ return str;
+ }
+ return NULL;
+}
+
+/* public api */
+TRex *trex_compile(const TRexChar *pattern,const TRexChar **error)
+{
+ TRex *exp = (TRex *)malloc(sizeof(TRex));
+ exp->_eol = exp->_bol = NULL;
+ exp->_p = pattern;
+ exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
+ exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
+ exp->_nsize = 0;
+ exp->_matches = 0;
+ exp->_nsubexpr = 0;
+ exp->_first = trex_newnode(exp,OP_EXPR);
+ exp->_error = error;
+ exp->_jmpbuf = malloc(sizeof(jmp_buf));
+ if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
+ int res = trex_list(exp);
+ exp->_nodes[exp->_first].left = res;
+ if(*exp->_p!='\0')
+ trex_error(exp,_SC("unexpected character"));
+#ifdef _DEBUG
+ {
+ int nsize,i;
+ TRexNode *t;
+ nsize = exp->_nsize;
+ t = &exp->_nodes[0];
+ scprintf(_SC("\n"));
+ for(i = 0;i < nsize; i++) {
+ if(exp->_nodes[i].type>MAX_CHAR)
+ scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
+ else
+ scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
+ scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
+ }
+ scprintf(_SC("\n"));
+ }
+#endif
+ exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
+ memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
+ }
+ else{
+ trex_free(exp);
+ return NULL;
+ }
+ return exp;
+}
+
+void trex_free(TRex *exp)
+{
+ if(exp) {
+ if(exp->_nodes) free(exp->_nodes);
+ if(exp->_jmpbuf) free(exp->_jmpbuf);
+ if(exp->_matches) free(exp->_matches);
+ free(exp);
+ }
+}
+
+TRexBool trex_match(TRex* exp,const TRexChar* text)
+{
+ const TRexChar* res = NULL;
+ exp->_bol = text;
+ exp->_eol = text + scstrlen(text);
+ exp->_currsubexp = 0;
+ res = trex_matchnode(exp,exp->_nodes,text,NULL);
+ if(res == NULL || res != exp->_eol)
+ 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)
+{
+ const TRexChar *cur = NULL;
+ int node = exp->_first;
+ if(text_begin >= text_end) return TRex_False;
+ exp->_bol = text_begin;
+ exp->_eol = text_end;
+ do {
+ cur = text_begin;
+ while(node != -1) {
+ exp->_currsubexp = 0;
+ cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
+ if(!cur)
+ break;
+ node = exp->_nodes[node].next;
+ }
+ *text_begin++;
+ } while(cur == NULL && text_begin != text_end);
+
+ if(cur == NULL)
+ return TRex_False;
+
+ --text_begin;
+
+ if(out_begin) *out_begin = text_begin;
+ if(out_end) *out_end = cur;
+ return TRex_True;
+}
+
+TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
+{
+ return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
+}
+
+int trex_getsubexpcount(TRex* exp)
+{
+ return exp->_nsubexpr;
+}
+
+TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
+{
+ if( n<0 || n >= exp->_nsubexpr) return TRex_False;
+ *subexp = exp->_matches[n];
+ return TRex_True;
+}
+
+
+//########################################################################
+//########################################################################
+//## E N D R E G E X P
+//########################################################################
+//########################################################################
+
+
+
//########################################################################
bool URI::parse(const String &str)
{
-
+ init();
+
parselen = str.size();
String tmp;
//########################################################################
//########################################################################
-
-
//########################################################################
-//# M A K E B A S E
+//# F I L E S E T
//########################################################################
/**
- * Base class for all classes in this file
+ * This is the descriptor for a <fileset> item
*/
-class MakeBase
+class FileSet
{
public:
- MakeBase()
- {}
- virtual ~MakeBase()
- {}
-
- /**
- * Return the URI of the file associated with this object
- */
- URI getURI()
- { return uri; }
/**
- * Set the uri to the given string
+ *
*/
- void setURI(const String &uristr)
- { uri.parse(uristr); }
+ FileSet()
+ {}
/**
- * Resolve another path relative to this one
+ *
*/
- String resolve(const String &otherPath);
+ FileSet(const FileSet &other)
+ { assign(other); }
/**
- * Get an element attribute, performing substitutions if necessary
+ *
*/
- bool getAttribute(Element *elem, const String &name, String &result);
+ FileSet &operator=(const FileSet &other)
+ { assign(other); return *this; }
/**
- * Get an element value, performing substitutions if necessary
+ *
*/
- bool getValue(Element *elem, String &result);
-
-protected:
+ virtual ~FileSet()
+ {}
/**
- * The path to the file associated with this object
- */
- URI uri;
-
-
+ *
+ */
+ String getDirectory()
+ { return directory; }
+
/**
- * Print a printf()-like formatted error message
+ *
*/
- void error(char *fmt, ...);
+ void setDirectory(const String &val)
+ { directory = val; }
/**
- * Print a printf()-like formatted trace message
+ *
*/
- void status(char *fmt, ...);
+ void setFiles(const std::vector<String> &val)
+ { files = val; }
/**
- * Print a printf()-like formatted trace message
+ *
*/
- void trace(char *fmt, ...);
-
+ std::vector<String> getFiles()
+ { return files; }
+
/**
*
*/
- String getSuffix(const String &fname);
+ void setIncludes(const std::vector<String> &val)
+ { includes = val; }
+
+ /**
+ *
+ */
+ std::vector<String> getIncludes()
+ { return includes; }
+
+ /**
+ *
+ */
+ void setExcludes(const std::vector<String> &val)
+ { excludes = val; }
+
+ /**
+ *
+ */
+ std::vector<String> getExcludes()
+ { return excludes; }
+
+ /**
+ *
+ */
+ unsigned int size()
+ { return files.size(); }
+
+ /**
+ *
+ */
+ String operator[](int index)
+ { return files[index]; }
+
+ /**
+ *
+ */
+ void clear()
+ {
+ directory = "";
+ files.clear();
+ includes.clear();
+ excludes.clear();
+ }
+
+
+private:
+
+ void assign(const FileSet &other)
+ {
+ directory = other.directory;
+ files = other.files;
+ includes = other.includes;
+ excludes = other.excludes;
+ }
+
+ String directory;
+ std::vector<String> files;
+ std::vector<String> includes;
+ std::vector<String> excludes;
+};
+
+
+
+
+//########################################################################
+//# M A K E B A S E
+//########################################################################
+/**
+ * Base class for all classes in this file
+ */
+class MakeBase
+{
+public:
+ MakeBase()
+ {}
+ virtual ~MakeBase()
+ {}
+
+ /**
+ * Return the URI of the file associated with this object
+ */
+ URI getURI()
+ { return uri; }
+
+ /**
+ * Set the uri to the given string
+ */
+ void setURI(const String &uristr)
+ { uri.parse(uristr); }
+
+ /**
+ * Resolve another path relative to this one
+ */
+ String resolve(const String &otherPath);
+
+ /**
+ * Get an element attribute, performing substitutions if necessary
+ */
+ bool getAttribute(Element *elem, const String &name, String &result);
+
+ /**
+ * Get an element value, performing substitutions if necessary
+ */
+ bool getValue(Element *elem, String &result);
+
+protected:
+
+ /**
+ * The path to the file associated with this object
+ */
+ URI uri;
+
+
+ /**
+ * Print a printf()-like formatted error message
+ */
+ void error(char *fmt, ...);
+
+ /**
+ * Print a printf()-like formatted trace message
+ */
+ void status(char *fmt, ...);
+
+ /**
+ * Print a printf()-like formatted trace message
+ */
+ void trace(char *fmt, ...);
+
+ /**
+ * Check if a given string matches a given regex pattern
+ */
+ bool regexMatch(const String &str, const String &pattern);
+
+ /**
+ *
+ */
+ String getSuffix(const String &fname);
/**
* Break up a string into substrings delimited the characters
* in delimiters. Null-length substrings are ignored
*/
std::vector<String> tokenize(const String &val,
- const String &delimiters);
+ const String &delimiters);
/**
* replace runs of whitespace with a space
/**
* Execute a shell command. Outbuf is a ref to a string
* to catch the result.
- */
+ */
bool executeCommand(const String &call,
- const String &inbuf,
- String &outbuf,
- String &errbuf);
+ const String &inbuf,
+ String &outbuf,
+ String &errbuf);
/**
* List all directories in a given base and starting directory
* It is usually called like:
- * bool ret = listDirectories("src", "", result);
- */
+ * bool ret = listDirectories("src", "", result);
+ */
bool listDirectories(const String &baseName,
const String &dirname,
std::vector<String> &res);
/**
- * Find all files in the named directory whose short names (no path) match
- * the given regex pattern
- */
+ * Find all files in the named directory
+ */
bool listFiles(const String &baseName,
const String &dirname,
- std::vector<String> &excludes,
- std::vector<String> &res);
+ std::vector<String> &result);
+
+ /**
+ * Perform a listing for a fileset
+ */
+ bool listFiles(MakeBase &propRef, FileSet &fileSet);
/**
* Parse a <patternset>
*/
- bool getPatternSet(Element *elem,
+ bool parsePatternSet(Element *elem,
MakeBase &propRef,
- std::vector<String> &includes,
- std::vector<String> &excludes);
+ std::vector<String> &includes,
+ std::vector<String> &excludes);
/**
* Parse a <fileset> entry, and determine which files
* should be included
*/
- bool getFileSet(Element *elem,
+ bool parseFileSet(Element *elem,
MakeBase &propRef,
- String &dir,
- std::vector<String> &result);
+ FileSet &fileSet);
/**
* Return this object's property list
/**
* Turn 'true' and 'false' into boolean values
- */
+ */
bool getBool(const String &str, bool &val);
/**
* Create a directory, making intermediate dirs
* if necessary
- */
+ */
bool createDirectory(const String &dirname);
/**
/**
* replace variable refs like ${a} with their values
- */
+ */
bool getSubstitutions(const String &s, String &result);
}
+
+/**
+ * Check if a given string matches a given regex pattern
+ */
+bool MakeBase::regexMatch(const String &str, const String &pattern)
+{
+ const TRexChar *terror = NULL;
+ const TRexChar *cpat = pattern.c_str();
+ TRex *expr = trex_compile(cpat, &terror);
+ if (!expr)
+ {
+ if (!terror)
+ terror = "undefined";
+ error("compilation error [%s]!\n", terror);
+ return false;
+ }
+
+ bool ret = true;
+
+ const TRexChar *cstr = str.c_str();
+ if (trex_match(expr, cstr))
+ {
+ ret = true;
+ }
+ else
+ {
+ ret = false;
+ }
+
+ trex_free(expr);
+
+ return ret;
+}
+
/**
* Return the suffix, if any, of a file name
*/
//Skip to first visible character
while (i<len)
{
- ch = s[i];
- if (ch == '\n' || ch == '\r'
- || !isspace(ch))
- break;
- i++;
- }
+ ch = s[i];
+ if (ch == '\n' || ch == '\r'
+ || !isspace(ch))
+ break;
+ i++;
+ }
//Copy the rest of the line
- while (i<len)
- {
- ch = s[i];
+ while (i<len)
+ {
+ ch = s[i];
if (ch == '\n' || ch == '\r')
{
if (ch != '\r')
*/
bool MakeBase::executeCommand(const String &command,
const String &inbuf,
- String &outbuf,
- String &errbuf)
+ String &outbuf,
+ String &errbuf)
{
status("============ cmd ============\n%s\n=============================",
- command.c_str());
+ command.c_str());
+ outbuf.clear();
+ errbuf.clear();
+
#ifdef __WIN32__
/*
if (!paramBuf)
{
error("executeCommand cannot allocate command buffer");
- return false;
+ return false;
}
strcpy(paramBuf, (char *)command.c_str());
HANDLE stdoutRead, stdoutWrite;
HANDLE stderrRead, stderrWrite;
if (!CreatePipe(&stdinRead, &stdinWrite, &saAttr, 0))
- {
- error("executeProgram: could not create pipe");
+ {
+ error("executeProgram: could not create pipe");
delete[] paramBuf;
- return false;
- }
+ return false;
+ }
SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0);
- if (!CreatePipe(&stdoutRead, &stdoutWrite, &saAttr, 0))
- {
- error("executeProgram: could not create pipe");
+ if (!CreatePipe(&stdoutRead, &stdoutWrite, &saAttr, 0))
+ {
+ error("executeProgram: could not create pipe");
delete[] paramBuf;
- return false;
- }
+ return false;
+ }
SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0);
- if (!CreatePipe(&stderrRead, &stderrWrite, &saAttr, 0))
- {
- error("executeProgram: could not create pipe");
+ if (!CreatePipe(&stderrRead, &stderrWrite, &saAttr, 0))
+ {
+ error("executeProgram: could not create pipe");
delete[] paramBuf;
- return false;
- }
+ return false;
+ }
SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0);
// Create the process
&piProcessInfo))
{
error("executeCommand : could not create process : %s",
- win32LastError().c_str());
+ win32LastError().c_str());
ret = false;
}
&bytesWritten, NULL))
{
error("executeCommand: could not write to pipe");
- return false;
- }
+ return false;
+ }
if (!CloseHandle(stdinWrite))
- {
+ {
error("executeCommand: could not close write pipe");
- return false;
- }
+ return false;
+ }
if (!CloseHandle(stdoutWrite))
- {
+ {
error("executeCommand: could not close read pipe");
- return false;
- }
+ return false;
+ }
if (!CloseHandle(stderrWrite))
- {
+ {
error("executeCommand: could not close read pipe");
- return false;
- }
- while (true)
+ return false;
+ }
+ while (true)
{
//trace("## stderr");
DWORD avail;
for (unsigned int i=0 ; i<bytesRead ; i++)
outbuf.push_back(readBuf[i]);
}
- DWORD exitCode;
+ DWORD exitCode;
GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
if (exitCode != STILL_ACTIVE)
break;
Sleep(100);
- }
+ }
//trace("outbuf:%s", outbuf.c_str());
if (!CloseHandle(stdoutRead))
{
}
errnum = pclose(f);
}
- outbuf = s;
- if (errnum < 0)
- {
- error("exec of command '%s' failed : %s",
- command.c_str(), strerror(errno));
- return false;
- }
- else
- return true;
+ outbuf = s;
+ if (errnum != 0)
+ {
+ error("exec of command '%s' failed : %s",
+ command.c_str(), strerror(errno));
+ return false;
+ }
+ else
+ return true;
#endif
}
bool MakeBase::listFiles(const String &baseDir,
const String &dirName,
- std::vector<String> &excludes,
std::vector<String> &res)
{
String fullDir = baseDir;
std::vector<String> subdirs;
DIR *dir = opendir(dirNative.c_str());
+ if (!dir)
+ {
+ error("Could not open directory %s : %s",
+ dirNative.c_str(), strerror(errno));
+ return false;
+ }
while (true)
{
struct dirent *de = readdir(dir);
fullChild.append("/");
fullChild.append(childName);
- if (std::find(excludes.begin(), excludes.end(), childName)
- != excludes.end())
- {
- //trace("EXCLUDED:%s", childName.c_str());
- continue;
- }
-
- struct stat finfo;
- String nativeName = getNativePath(fullChild);
- if (stat(nativeName.c_str(), &finfo)<0)
- {
- error("cannot stat file:%s", childName.c_str());
- return false;
- }
- else if (S_ISDIR(finfo.st_mode))
+ if (isDirectory(fullChild))
{
//trace("directory: %s", childName.c_str());
- if (!listFiles(baseDir, childName, excludes, res))
+ if (!listFiles(baseDir, childName, res))
return false;
+ continue;
}
- else if (!S_ISREG(finfo.st_mode))
- {
- trace("not regular: %s", childName.c_str());
- }
- else
+ else if (!isRegularFile(fullChild))
{
- res.push_back(childName);
+ error("unknown file:%s", childName.c_str());
+ return false;
}
+
+ //all done!
+ res.push_back(childName);
+
}
closedir(dir);
}
+bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet)
+{
+ String baseDir = propRef.resolve(fileSet.getDirectory());
+ std::vector<String> fileList;
+ if (!listFiles(baseDir, "", fileList))
+ return false;
+
+ std::vector<String> includes = fileSet.getIncludes();
+ std::vector<String> excludes = fileSet.getExcludes();
+
+ std::vector<String> incs;
+ std::vector<String>::iterator iter;
+
+ std::sort(fileList.begin(), fileList.end());
+
+ //If there are <includes>, then add files to the output
+ //in the order of the include list
+ if (includes.size()==0)
+ incs = fileList;
+ else
+ {
+ for (iter = includes.begin() ; iter != includes.end() ; iter++)
+ {
+ String pattern = *iter;
+ std::vector<String>::iterator siter;
+ for (siter = fileList.begin() ; siter != fileList.end() ; siter++)
+ {
+ String s = *siter;
+ if (regexMatch(s, pattern))
+ {
+ //trace("INCLUDED:%s", s.c_str());
+ incs.push_back(s);
+ }
+ }
+ }
+ }
+
+ //Now trim off the <excludes>
+ std::vector<String> res;
+ for (iter = incs.begin() ; iter != incs.end() ; iter++)
+ {
+ String s = *iter;
+ bool skipme = false;
+ std::vector<String>::iterator siter;
+ for (siter = excludes.begin() ; siter != excludes.end() ; siter++)
+ {
+ String pattern = *siter;
+ if (regexMatch(s, pattern))
+ {
+ //trace("EXCLUDED:%s", s.c_str());
+ skipme = true;
+ break;
+ }
+ }
+ if (!skipme)
+ res.push_back(s);
+ }
+
+ fileSet.setFiles(res);
+ return true;
+}
{
char ch = s[i];
if (ch == '$' && s[i+1] == '{')
- {
+ {
String varname;
- int j = i+2;
- for ( ; j<len ; j++)
- {
- ch = s[j];
- if (ch == '$' && s[j+1] == '{')
- {
- error("attribute %s cannot have nested variable references",
- s.c_str());
- return false;
- }
- else if (ch == '}')
- {
- std::map<String, String>::iterator iter;
- iter = properties.find(trim(varname));
- if (iter != properties.end())
- {
- val.append(iter->second);
- }
- else
- {
- error("property ${%s} not found", varname.c_str());
- return false;
- }
- break;
- }
- else
- {
- varname.push_back(ch);
- }
- }
- i = j;
- }
- else
- {
- val.push_back(ch);
- }
+ int j = i+2;
+ for ( ; j<len ; j++)
+ {
+ ch = s[j];
+ if (ch == '$' && s[j+1] == '{')
+ {
+ error("attribute %s cannot have nested variable references",
+ s.c_str());
+ return false;
+ }
+ else if (ch == '}')
+ {
+ std::map<String, String>::iterator iter;
+ iter = properties.find(trim(varname));
+ if (iter != properties.end())
+ {
+ val.append(iter->second);
+ }
+ else
+ {
+ error("property ${%s} not found", varname.c_str());
+ return false;
+ }
+ break;
+ }
+ else
+ {
+ varname.push_back(ch);
+ }
+ }
+ i = j;
+ }
+ else
+ {
+ val.push_back(ch);
+ }
}
result = val;
return true;
/**
* Turn 'true' and 'false' into boolean values
- */
+ */
bool MakeBase::getBool(const String &str, bool &val)
{
if (str == "true")
/**
* Parse a <patternset> entry
*/
-bool MakeBase::getPatternSet(Element *elem,
+bool MakeBase::parsePatternSet(Element *elem,
MakeBase &propRef,
- std::vector<String> &includes,
- std::vector<String> &excludes
- )
+ std::vector<String> &includes,
+ std::vector<String> &excludes
+ )
{
std::vector<Element *> children = elem->getChildren();
for (unsigned int i=0 ; i<children.size() ; i++)
if (tagName == "exclude")
{
String fname;
- if (!propRef.getAttribute(child, "name", fname))
- return false;
+ if (!propRef.getAttribute(child, "name", fname))
+ return false;
//trace("EXCLUDE: %s", fname.c_str());
excludes.push_back(fname);
}
else if (tagName == "include")
{
String fname;
- if (!propRef.getAttribute(child, "name", fname))
- return false;
+ if (!propRef.getAttribute(child, "name", fname))
+ return false;
//trace("INCLUDE: %s", fname.c_str());
includes.push_back(fname);
}
* Parse a <fileset> entry, and determine which files
* should be included
*/
-bool MakeBase::getFileSet(Element *elem,
+bool MakeBase::parseFileSet(Element *elem,
MakeBase &propRef,
- String &dir,
- std::vector<String> &result)
+ FileSet &fileSet)
{
String name = elem->getName();
if (name != "fileset")
std::vector<String> excludes;
//A fileset has one implied patternset
- if (!getPatternSet(elem, propRef, includes, excludes))
+ if (!parsePatternSet(elem, propRef, includes, excludes))
{
return false;
}
String tagName = child->getName();
if (tagName == "patternset")
{
- if (!getPatternSet(child, propRef, includes, excludes))
+ if (!parsePatternSet(child, propRef, includes, excludes))
{
return false;
}
}
}
+ String dir;
//Now do the stuff
//Get the base directory for reading file names
if (!propRef.getAttribute(elem, "dir", dir))
return false;
+ fileSet.setDirectory(dir);
+ fileSet.setIncludes(includes);
+ fileSet.setExcludes(excludes);
+
+ /*
std::vector<String> fileList;
if (dir.size() > 0)
{
String baseDir = propRef.resolve(dir);
- if (!listFiles(baseDir, "", excludes, fileList))
- return false;
- }
-
- std::vector<String>::iterator iter;
- for (iter=includes.begin() ; iter!=includes.end() ; iter++)
+ 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++)
{
- String fname = *iter;
- fileList.push_back(fname);
+ trace("RES:%s", result[i].c_str());
}
-
- result = fileList;
-
- /*
- for (unsigned int i=0 ; i<result.size() ; i++)
- {
- trace("RES:%s", result[i].c_str());
- }
*/
- std::sort(fileList.begin(), fileList.end());
return true;
}
/**
* Create a directory, making intermediate dirs
* if necessary
- */
+ */
bool MakeBase::createDirectory(const String &dirname)
{
//trace("## createDirectory: %s", dirname.c_str());
struct stat finfo;
String nativeDir = getNativePath(dirname);
char *cnative = (char *) nativeDir.c_str();
- if (stat(dirname.c_str(), &finfo)==0)
+#ifdef __WIN32__
+ if (strlen(cnative)==2 && cnative[1]==':')
+ return true;
+#endif
+ if (stat(cnative, &finfo)==0)
{
if (!S_ISDIR(finfo.st_mode))
{
error("mkdir: file %s exists but is not a directory",
- cnative);
+ cnative);
return false;
}
else //exists
//## 2: pull off the last path segment, if any,
//## to make the dir 'above' this one, if necessary
unsigned int pos = dirname.find_last_of('/');
- if (pos != dirname.npos)
+ if (pos>0 && pos != dirname.npos)
{
String subpath = dirname.substr(0, pos);
+ //A letter root (c:) ?
if (!createDirectory(subpath))
return false;
}
//## 3: now make
+#ifdef __WIN32__
if (mkdir(cnative)<0)
+#else
+ if (mkdir(cnative, S_IRWXU | S_IRWXG | S_IRWXO)<0)
+#endif
{
- error("cannot make directory %s", cnative);
+ error("cannot make directory '%s' : %s",
+ cnative, strerror(errno));
return false;
}
else if (S_ISDIR(finfo.st_mode))
{
//trace("DEL dir: %s", childName.c_str());
- if (!removeDirectory(childName))
- {
- return false;
- }
+ if (!removeDirectory(childName))
+ {
+ return false;
+ }
}
else if (!S_ISREG(finfo.st_mode))
{
- trace("not regular: %s", cnative);
+ //trace("not regular: %s", cnative);
}
else
{
if (remove(cnative)<0)
{
error("error deleting %s : %s",
- cnative, strerror(errno));
- return false;
- }
- }
+ cnative, strerror(errno));
+ return false;
+ }
+ }
}
closedir(dir);
if (stat(srcNative.c_str(), &srcinfo)<0)
{
error("source file %s for copy does not exist",
- srcNative.c_str());
+ srcNative.c_str());
return false;
}
if (!CopyFile(srcNative.c_str(), destNative.c_str(), false))
{
error("copyFile from %s to %s failed",
- srcNative.c_str(), destNative.c_str());
+ srcNative.c_str(), destNative.c_str());
return false;
}
//Exists?
if (stat(native.c_str(), &finfo)<0)
- return false;
+ return false;
//check the file mode
if (!S_ISREG(finfo.st_mode))
- return false;
+ return false;
return true;
}
//Exists?
if (stat(native.c_str(), &finfo)<0)
- return false;
+ return false;
//check the file mode
if (!S_ISDIR(finfo.st_mode))
- return false;
+ return false;
return true;
}
//IF source does not exist, NOT newer
if (stat(nativeA.c_str(), &infoA)<0)
{
- return false;
- }
+ return false;
+ }
String nativeB = getNativePath(fileB);
struct stat infoB;
//IF dest does not exist, YES, newer
if (stat(nativeB.c_str(), &infoB)<0)
{
- return true;
- }
+ return true;
+ }
//check the actual times
if (infoA.st_mtime > infoB.st_mtime)
{
- return true;
- }
+ return true;
+ }
return false;
}
void PkgConfig::dumpAttrs()
{
- trace("### PkgConfig attributes for %s", fileName.c_str());
+ //trace("### PkgConfig attributes for %s", fileName.c_str());
std::map<String, String>::iterator iter;
for (iter=attrs.begin() ; iter!=attrs.end() ; iter++)
{
}
fclose(f);
- trace("####### File:\n%s", buf.c_str());
+ //trace("####### File:\n%s", buf.c_str());
if (!parse(buf))
{
return false;
/**
* Load a dependency file, generating one if necessary
*/
- std::vector<DepRec> getDepFile(const String &fileName);
+ std::vector<DepRec> getDepFile(const String &fileName,
+ bool forceRefresh);
/**
* Save a dependency file
int depFileSize;
char *depFileBuf;
-
+
+ static const int readBufSize = 8192;
+ char readBuf[8193];//byte larger
};
String sfx;
parseName(fileName, path, basename, sfx);
if (sfx == "cpp" || sfx == "c" || sfx == "cxx" ||
- sfx == "cc" || sfx == "CC")
+ sfx == "cc" || sfx == "CC")
{
FileRec *fe = new FileRec(FileRec::CFILE);
fe->path = path;
return false;
}
String buf;
- while (true)
+ while (!feof(f))
{
- int ch = fgetc(f);
- if (ch < 0)
- break;
- buf.push_back((char)ch);
+ int len = fread(readBuf, 1, readBufSize, f);
+ readBuf[len] = '\0';
+ buf.append(readBuf);
}
fclose(f);
if (frec->type == FileRec::OFILE)
{
fprintf(f, "<object path='%s' name='%s' suffix='%s'>\n",
- frec->path.c_str(), frec->baseName.c_str(), frec->suffix.c_str());
+ frec->path.c_str(), frec->baseName.c_str(), frec->suffix.c_str());
std::map<String, FileRec *>::iterator citer;
for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
{
Element *root = parser.parseFile(depFile.c_str());
if (!root)
{
- error("Could not open %s for reading", depFile.c_str());
+ //error("Could not open %s for reading", depFile.c_str());
return result;
}
/**
* This loads the dependency cache.
*/
-std::vector<DepRec> DepTool::getDepFile(const String &depFile)
+std::vector<DepRec> DepTool::getDepFile(const String &depFile,
+ bool forceRefresh)
{
- std::vector<DepRec> result = loadDepFile(depFile);
- if (result.size() == 0)
+ std::vector<DepRec> result;
+ if (forceRefresh)
{
generateDependencies(depFile);
result = loadDepFile(depFile);
}
+ else
+ {
+ //try once
+ result = loadDepFile(depFile);
+ if (result.size() == 0)
+ {
+ //fail? try again
+ generateDependencies(depFile);
+ result = loadDepFile(depFile);
+ }
+ }
return result;
}
typedef enum
{
TASK_NONE,
- TASK_AR,
TASK_CC,
TASK_COPY,
TASK_DELETE,
TASK_MSGFMT,
TASK_RANLIB,
TASK_RC,
+ TASK_SHAREDLIB,
+ TASK_STATICLIB,
TASK_STRIP,
TASK_TSTAMP
} TaskType;
-
-/**
- * Run the "ar" command to archive .o's into a .a
- */
-class TaskAr : public Task
-{
-public:
-
- TaskAr(MakeBase &par) : Task(par)
- {
- type = TASK_AR; name = "ar";
- command = "ar crv";
- }
-
- virtual ~TaskAr()
- {}
-
- virtual bool execute()
- {
- //trace("###########HERE %d", fileSet.size());
- bool doit = false;
-
- String fullOut = parent.resolve(fileName);
- //trace("ar fullout: %s", fullOut.c_str());
-
-
- for (unsigned int i=0 ; i<fileSet.size() ; i++)
- {
- String fname;
- if (fileSetDir.size()>0)
- {
- fname.append(fileSetDir);
- fname.append("/");
- }
- fname.append(fileSet[i]);
- String fullName = parent.resolve(fname);
- //trace("ar : %s/%s", fullOut.c_str(), fullName.c_str());
- if (isNewerThan(fullName, fullOut))
- doit = true;
- }
- //trace("Needs it:%d", doit);
- if (!doit)
- {
- return true;
- }
-
- String cmd = command;
- cmd.append(" ");
- cmd.append(fullOut);
- for (unsigned int i=0 ; i<fileSet.size() ; i++)
- {
- String fname;
- if (fileSetDir.size()>0)
- {
- fname.append(fileSetDir);
- fname.append("/");
- }
- fname.append(fileSet[i]);
- String fullName = parent.resolve(fname);
-
- cmd.append(" ");
- cmd.append(fullName);
- }
-
- String outString, errString;
- if (!executeCommand(cmd.c_str(), "", outString, errString))
- {
- error("AR problem: %s", errString.c_str());
- return false;
- }
-
- return true;
- }
-
- virtual bool parse(Element *elem)
- {
- if (!parent.getAttribute(elem, "file", fileName))
- return false;
-
- std::vector<Element *> children = elem->getChildren();
- for (unsigned int i=0 ; i<children.size() ; i++)
- {
- Element *child = children[i];
- String tagName = child->getName();
- if (tagName == "fileset")
- {
- if (!getFileSet(child, parent, fileSetDir, fileSet))
- return false;
- }
- }
- return true;
- }
-
-private:
-
- String command;
- String fileName;
- String fileSetDir;
- std::vector<String> fileSet;
-
-};
-
-
/**
* This task runs the C/C++ compiler. The compiler is invoked
* for all .c or .cpp files which are newer than their correcsponding
TaskCC(MakeBase &par) : Task(par)
{
- type = TASK_CC; name = "cc";
- ccCommand = "gcc";
- cxxCommand = "g++";
- source = ".";
- dest = ".";
- flags = "";
- defines = "";
- includes = "";
- sourceFiles.clear();
+ type = TASK_CC; name = "cc";
+ ccCommand = "gcc";
+ cxxCommand = "g++";
+ source = ".";
+ dest = ".";
+ flags = "";
+ defines = "";
+ includes = "";
+ fileSet.clear();
}
virtual ~TaskCC()
{}
+ virtual bool needsCompiling(const DepRec &depRec,
+ const String &src, const String &dest)
+ {
+ return false;
+ }
+
virtual bool execute()
{
+ if (!listFiles(parent, fileSet))
+ return false;
+
+ bool refreshCache = false;
+ String fullName = parent.resolve("build.dep");
+ if (isNewerThan(parent.getURI().getPath(), fullName))
+ {
+ status(" : regenerating C/C++ dependency cache");
+ refreshCache = true;
+ }
+
DepTool depTool;
depTool.setSourceDirectory(source);
- depTool.setFileList(sourceFiles);
- std::vector<DepRec> deps = depTool.getDepFile("build.dep");
+ depTool.setFileList(fileSet.getFiles());
+ std::vector<DepRec> deps =
+ depTool.getDepFile("build.dep", refreshCache);
String incs;
incs.append("-I");
String sfx = dep.suffix;
String command = ccCommand;
if (sfx == "cpp" || sfx == "c++" || sfx == "cc"
- || sfx == "CC")
- command = cxxCommand;
+ || sfx == "CC")
+ command = cxxCommand;
//## Make paths
String destPath = dest;
String srcPath = source;
if (dep.path.size()>0)
- {
+ {
destPath.append("/");
- destPath.append(dep.path);
+ destPath.append(dep.path);
srcPath.append("/");
- srcPath.append(dep.path);
- }
+ srcPath.append(dep.path);
+ }
//## Make sure destination directory exists
- if (!createDirectory(destPath))
- return false;
-
+ if (!createDirectory(destPath))
+ return false;
+
//## Check whether it needs to be done
- String destFullName = destPath;
- destFullName.append("/");
- destFullName.append(dep.name);
- destFullName.append(".o");
- String srcFullName = srcPath;
- srcFullName.append("/");
- srcFullName.append(dep.name);
- srcFullName.append(".");
- srcFullName.append(dep.suffix);
- if (!isNewerThan(srcFullName, destFullName))
+ String destName;
+ if (destPath.size()>0)
+ {
+ destName.append(destPath);
+ destName.append("/");
+ }
+ destName.append(dep.name);
+ destName.append(".o");
+ String destFullName = parent.resolve(destName);
+ String srcName;
+ if (srcPath.size()>0)
+ {
+ srcName.append(srcPath);
+ srcName.append("/");
+ }
+ srcName.append(dep.name);
+ srcName.append(".");
+ srcName.append(dep.suffix);
+ String srcFullName = parent.resolve(srcName);
+ bool compileMe = false;
+ if (isNewerThan(srcFullName, destFullName))
+ {
+ status(" : compile of %s required by %s",
+ destFullName.c_str(), srcFullName.c_str());
+ compileMe = true;
+ }
+ else
+ {
+ for (unsigned int i=0 ; i<dep.files.size() ; i++)
+ {
+ String depName;
+ if (srcPath.size()>0)
+ {
+ depName.append(srcPath);
+ depName.append("/");
+ }
+ depName.append(dep.files[i]);
+ String depFullName = parent.resolve(depName);
+ if (isNewerThan(depFullName, destFullName))
+ {
+ status(" : compile of %s required by %s",
+ destFullName.c_str(), depFullName.c_str());
+ compileMe = true;
+ break;
+ }
+ }
+ }
+ if (!compileMe)
{
- //trace("%s skipped", srcFullName.c_str());
continue;
}
String cmd = command;
cmd.append(" -c ");
cmd.append(flags);
- cmd.append(" ");
+ cmd.append(" ");
cmd.append(defines);
- cmd.append(" ");
+ cmd.append(" ");
cmd.append(incs);
- cmd.append(" ");
- cmd.append(srcFullName);
+ cmd.append(" ");
+ cmd.append(srcFullName);
cmd.append(" -o ");
- cmd.append(destFullName);
+ cmd.append(destFullName);
//## Execute the command
}
else if (tagName == "fileset")
{
- if (!getFileSet(child, parent, source, sourceFiles))
+ if (!parseFileSet(child, parent, fileSet))
return false;
+ source = fileSet.getDirectory();
}
}
String flags;
String defines;
String includes;
- std::vector<String> sourceFiles;
+ FileSet fileSet;
};
TaskCopy(MakeBase &par) : Task(par)
{
- type = TASK_COPY; name = "copy";
- cptype = CP_NONE;
- verbose = false;
- haveFileSet = false;
- }
+ type = TASK_COPY; name = "copy";
+ cptype = CP_NONE;
+ verbose = false;
+ haveFileSet = false;
+ }
virtual ~TaskCopy()
{}
{
if (fileName.size()>0)
{
- status(" : %s", fileName.c_str());
+ status(" : %s to %s",
+ fileName.c_str(), toFileName.c_str());
String fullSource = parent.resolve(fileName);
String fullDest = parent.resolve(toFileName);
//trace("copy %s to file %s", fullSource.c_str(),
- // fullDest.c_str());
- if (!isRegularFile(fullSource))
- {
+ // fullDest.c_str());
+ if (!isRegularFile(fullSource))
+ {
error("copy : file %s does not exist", fullSource.c_str());
- return false;
- }
+ return false;
+ }
if (!isNewerThan(fullSource, fullDest))
{
return true;
{
if (haveFileSet)
{
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = fileSet.getDirectory();
+
+ status(" : %s to %s",
+ fileSetDir.c_str(), toDirName.c_str());
+
int nrFiles = 0;
- status(" : %s", fileSetDir.c_str());
for (unsigned int i=0 ; i<fileSet.size() ; i++)
{
String fileName = fileSet[i];
String baseFileSetDir = fileSetDir;
unsigned int pos = baseFileSetDir.find_last_of('/');
if (pos!=baseFileSetDir.npos &&
- pos < baseFileSetDir.size()-1)
+ pos < baseFileSetDir.size()-1)
baseFileSetDir =
- baseFileSetDir.substr(pos+1,
- baseFileSetDir.size());
- //Now make the new path
+ baseFileSetDir.substr(pos+1,
+ baseFileSetDir.size());
+ //Now make the new path
String destPath;
if (toDirName.size()>0)
{
String fullDest = parent.resolve(destPath);
//trace("fileName:%s", fileName.c_str());
//trace("copy %s to new dir : %s", fullSource.c_str(),
- // fullDest.c_str());
+ // fullDest.c_str());
if (!isNewerThan(fullSource, fullDest))
{
//trace("copy skipping %s", fullSource.c_str());
{
//For file->dir we want only the basename of
//the source appended to the dest dir
- status(" : %s", fileName.c_str());
+ status(" : %s to %s",
+ fileName.c_str(), toDirName.c_str());
String baseName = fileName;
unsigned int pos = baseName.find_last_of('/');
if (pos!=baseName.npos && pos<baseName.size()-1)
destPath.append(baseName);
String fullDest = parent.resolve(destPath);
//trace("copy %s to new dir : %s", fullSource.c_str(),
- // fullDest.c_str());
- if (!isRegularFile(fullSource))
- {
+ // fullDest.c_str());
+ if (!isRegularFile(fullSource))
+ {
error("copy : file %s does not exist", fullSource.c_str());
- return false;
- }
+ return false;
+ }
if (!isNewerThan(fullSource, fullDest))
{
return true;
String tagName = child->getName();
if (tagName == "fileset")
{
- if (!getFileSet(child, parent, fileSetDir, fileSet))
+ if (!parseFileSet(child, parent, fileSet))
{
error("problem getting fileset");
- return false;
- }
- haveFileSet = true;
+ return false;
+ }
+ haveFileSet = true;
}
}
//Perform validity checks
- if (fileName.size()>0 && fileSet.size()>0)
- {
- error("<copy> can only have one of : file= and <fileset>");
- return false;
- }
+ if (fileName.size()>0 && fileSet.size()>0)
+ {
+ error("<copy> can only have one of : file= and <fileset>");
+ return false;
+ }
if (toFileName.size()>0 && toDirName.size()>0)
{
error("<copy> can only have one of : tofile= or todir=");
error("a <copy> task with a <fileset> must have : todir=");
return false;
}
- if (cptype == CP_TOFILE && fileName.size()==0)
- {
- error("<copy> tofile= must be associated with : file=");
- return false;
- }
- if (cptype == CP_TODIR && fileName.size()==0 && !haveFileSet)
- {
- error("<copy> todir= must be associated with : file= or <fileset>");
- return false;
- }
+ if (cptype == CP_TOFILE && fileName.size()==0)
+ {
+ error("<copy> tofile= must be associated with : file=");
+ return false;
+ }
+ if (cptype == CP_TODIR && fileName.size()==0 && !haveFileSet)
+ {
+ error("<copy> todir= must be associated with : file= or <fileset>");
+ return false;
+ }
return true;
}
int cptype;
String fileName;
- String fileSetDir;
- std::vector<String> fileSet;
+ FileSet fileSet;
String toFileName;
String toDirName;
bool verbose;
TaskDelete(MakeBase &par) : Task(par)
{
- type = TASK_DELETE;
- name = "delete";
- delType = DEL_FILE;
+ type = TASK_DELETE;
+ name = "delete";
+ delType = DEL_FILE;
verbose = false;
quiet = false;
failOnError = true;
- }
+ }
virtual ~TaskDelete()
{}
TaskLink(MakeBase &par) : Task(par)
{
- type = TASK_LINK; name = "link";
- command = "g++";
- }
+ type = TASK_LINK; name = "link";
+ command = "g++";
+ doStrip = false;
+ stripCommand = "strip";
+ objcopyCommand = "objcopy";
+ }
virtual ~TaskLink()
{}
virtual bool execute()
{
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = fileSet.getDirectory();
+ //trace("%d files in %s", fileSet.size(), fileSetDir.c_str());
bool doit = false;
String fullTarget = parent.resolve(fileName);
String cmd = command;
cmd.append(" ");
String obj;
if (fileSetDir.size()>0)
- {
- obj.append(fileSetDir);
+ {
+ obj.append(fileSetDir);
obj.append("/");
}
obj.append(fileSet[i]);
String fullObj = parent.resolve(obj);
cmd.append(fullObj);
+ //trace("link: tgt:%s obj:%s", fullTarget.c_str(),
+ // fullObj.c_str());
if (isNewerThan(fullObj, fullTarget))
doit = true;
}
//trace("LINK cmd:%s", cmd.c_str());
- String outString, errString;
- if (!executeCommand(cmd.c_str(), "", outString, errString))
+ String outbuf, errbuf;
+ if (!executeCommand(cmd.c_str(), "", outbuf, errbuf))
{
- error("LINK problem: %s", errString.c_str());
+ error("LINK problem: %s", errbuf.c_str());
return false;
}
+
+ if (symFileName.size()>0)
+ {
+ String symFullName = parent.resolve(symFileName);
+ cmd = objcopyCommand;
+ cmd.append(" --only-keep-debug ");
+ cmd.append(getNativePath(fullTarget));
+ cmd.append(" ");
+ cmd.append(getNativePath(symFullName));
+ if (!executeCommand(cmd, "", outbuf, errbuf))
+ {
+ error("<strip> symbol file failed : %s", errbuf.c_str());
+ return false;
+ }
+ }
+
+ if (doStrip)
+ {
+ cmd = stripCommand;
+ cmd.append(" ");
+ cmd.append(getNativePath(fullTarget));
+ if (!executeCommand(cmd, "", outbuf, errbuf))
+ {
+ error("<strip> failed : %s", errbuf.c_str());
+ return false;
+ }
+ }
+
return true;
}
virtual bool parse(Element *elem)
{
- if (!parent.getAttribute(elem, "command", command))
+ String s;
+ if (!parent.getAttribute(elem, "command", s))
return false;
+ if (s.size()>0)
+ command = s;
+ if (!parent.getAttribute(elem, "objcopycommand", s))
+ return false;
+ if (s.size()>0)
+ objcopyCommand = s;
+ if (!parent.getAttribute(elem, "stripcommand", s))
+ return false;
+ if (s.size()>0)
+ stripCommand = s;
if (!parent.getAttribute(elem, "out", fileName))
return false;
+ if (!parent.getAttribute(elem, "strip", s))
+ return false;
+ if (s.size()>0 && !getBool(s, doStrip))
+ return false;
+ if (!parent.getAttribute(elem, "symfile", symFileName))
+ return false;
std::vector<Element *> children = elem->getChildren();
for (unsigned int i=0 ; i<children.size() ; i++)
String tagName = child->getName();
if (tagName == "fileset")
{
- if (!getFileSet(child, parent, fileSetDir, fileSet))
+ if (!parseFileSet(child, parent, fileSet))
return false;
}
else if (tagName == "flags")
private:
- String command;
- String fileName;
- String flags;
- String libs;
- String fileSetDir;
- std::vector<String> fileSet;
+ String command;
+ String fileName;
+ String flags;
+ String libs;
+ FileSet fileSet;
+ bool doStrip;
+ String symFileName;
+ String stripCommand;
+ String objcopyCommand;
};
}
for (unsigned int i=0 ; i<text.size() ; i++)
fputc(text[i], f);
+ fputc('\n', f);
fclose(f);
return true;
}
error("<mkdir> requires 'dir=\"dirname\"' attribute");
return false;
}
- //trace("dirname:%s", dirName.c_str());
return true;
}
TaskMsgFmt(MakeBase &par) : Task(par)
{
- type = TASK_MSGFMT;
- name = "msgfmt";
- command = "msgfmt";
- }
+ type = TASK_MSGFMT;
+ name = "msgfmt";
+ command = "msgfmt";
+ owndir = false;
+ outName = "";
+ }
virtual ~TaskMsgFmt()
{}
virtual bool execute()
{
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = fileSet.getDirectory();
+
//trace("msgfmt: %d", fileSet.size());
for (unsigned int i=0 ; i<fileSet.size() ; i++)
{
if (getSuffix(fileName) != "po")
continue;
String sourcePath;
- if (fileSetDir.size()>0)
- {
- sourcePath.append(fileSetDir);
+ if (fileSetDir.size()>0)
+ {
+ sourcePath.append(fileSetDir);
sourcePath.append("/");
}
sourcePath.append(fileName);
String fullSource = parent.resolve(sourcePath);
String destPath;
- if (toDirName.size()>0)
- {
- destPath.append(toDirName);
+ if (toDirName.size()>0)
+ {
+ destPath.append(toDirName);
destPath.append("/");
}
- destPath.append(fileName);
- destPath[destPath.size()-2] = 'm';
+ if (owndir)
+ {
+ String subdir = fileName;
+ unsigned int pos = subdir.find_last_of('.');
+ if (pos != subdir.npos)
+ subdir = subdir.substr(0, pos);
+ destPath.append(subdir);
+ destPath.append("/");
+ }
+ //Pick the output file name
+ if (outName.size() > 0)
+ {
+ destPath.append(outName);
+ }
+ else
+ {
+ destPath.append(fileName);
+ destPath[destPath.size()-2] = 'm';
+ }
+
String fullDest = parent.resolve(destPath);
if (!isNewerThan(fullSource, fullDest))
- String outString, errString;
- if (!executeCommand(cmd.c_str(), "", outString, errString))
- {
- error("<msgfmt> problem: %s", errString.c_str());
- return false;
- }
+ String outString, errString;
+ if (!executeCommand(cmd.c_str(), "", outString, errString))
+ {
+ error("<msgfmt> problem: %s", errString.c_str());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool parse(Element *elem)
+ {
+ String s;
+ if (!parent.getAttribute(elem, "command", s))
+ return false;
+ if (s.size()>0)
+ command = s;
+ if (!parent.getAttribute(elem, "todir", toDirName))
+ return false;
+ if (!parent.getAttribute(elem, "out", outName))
+ return false;
+ if (!parent.getAttribute(elem, "owndir", s))
+ return false;
+ if (s.size()>0 && !getBool(s, owndir))
+ return false;
+
+ std::vector<Element *> children = elem->getChildren();
+ for (unsigned int i=0 ; i<children.size() ; i++)
+ {
+ Element *child = children[i];
+ String tagName = child->getName();
+ if (tagName == "fileset")
+ {
+ if (!parseFileSet(child, parent, fileSet))
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+
+ String command;
+ String toDirName;
+ String outName;
+ FileSet fileSet;
+ bool owndir;
+
+};
+
+
+
+
+
+/**
+ * Process an archive to allow random access
+ */
+class TaskRanlib : public Task
+{
+public:
+
+ TaskRanlib(MakeBase &par) : Task(par)
+ {
+ type = TASK_RANLIB; name = "ranlib";
+ command = "ranlib";
+ }
+
+ virtual ~TaskRanlib()
+ {}
+
+ virtual bool execute()
+ {
+ String fullName = parent.resolve(fileName);
+ //trace("fullDir:%s", fullDir.c_str());
+ String cmd = command;
+ cmd.append(" ");
+ cmd.append(fullName);
+ String outbuf, errbuf;
+ if (!executeCommand(cmd, "", outbuf, errbuf))
+ return false;
+ return true;
+ }
+
+ virtual bool parse(Element *elem)
+ {
+ String s;
+ if (!parent.getAttribute(elem, "command", s))
+ return false;
+ if (s.size()>0)
+ command = s;
+ if (!parent.getAttribute(elem, "file", fileName))
+ return false;
+ if (fileName.size() == 0)
+ {
+ error("<ranlib> requires 'file=\"fileNname\"' attribute");
+ return false;
+ }
+ return true;
+ }
+
+private:
+
+ String fileName;
+ String command;
+};
+
+
+
+/**
+ * Run the "ar" command to archive .o's into a .a
+ */
+class TaskRC : public Task
+{
+public:
+
+ TaskRC(MakeBase &par) : Task(par)
+ {
+ type = TASK_RC; name = "rc";
+ command = "windres";
+ }
+
+ virtual ~TaskRC()
+ {}
+
+ virtual bool execute()
+ {
+ String fullFile = parent.resolve(fileName);
+ String fullOut = parent.resolve(outName);
+ if (!isNewerThan(fullFile, fullOut))
+ return true;
+ String cmd = command;
+ cmd.append(" -o ");
+ cmd.append(fullOut);
+ cmd.append(" ");
+ cmd.append(flags);
+ cmd.append(" ");
+ cmd.append(fullFile);
+
+ String outString, errString;
+ if (!executeCommand(cmd.c_str(), "", outString, errString))
+ {
+ error("RC problem: %s", errString.c_str());
+ return false;
+ }
+ return true;
+ }
+
+ virtual bool parse(Element *elem)
+ {
+ if (!parent.getAttribute(elem, "command", command))
+ return false;
+ if (!parent.getAttribute(elem, "file", fileName))
+ return false;
+ if (!parent.getAttribute(elem, "out", outName))
+ return false;
+ std::vector<Element *> children = elem->getChildren();
+ for (unsigned int i=0 ; i<children.size() ; i++)
+ {
+ Element *child = children[i];
+ String tagName = child->getName();
+ if (tagName == "flags")
+ {
+ if (!parent.getValue(child, flags))
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+
+ String command;
+ String flags;
+ String fileName;
+ String outName;
+
+};
+
+
+
+/**
+ * Collect .o's into a .so or DLL
+ */
+class TaskSharedLib : public Task
+{
+public:
+
+ TaskSharedLib(MakeBase &par) : Task(par)
+ {
+ type = TASK_SHAREDLIB; name = "dll";
+ command = "ar crv";
+ }
+
+ virtual ~TaskSharedLib()
+ {}
+
+ virtual bool execute()
+ {
+ //trace("###########HERE %d", fileSet.size());
+ bool doit = false;
+
+ String fullOut = parent.resolve(fileName);
+ //trace("ar fullout: %s", fullOut.c_str());
+
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = fileSet.getDirectory();
+
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
+ {
+ String fname;
+ if (fileSetDir.size()>0)
+ {
+ fname.append(fileSetDir);
+ fname.append("/");
+ }
+ fname.append(fileSet[i]);
+ String fullName = parent.resolve(fname);
+ //trace("ar : %s/%s", fullOut.c_str(), fullName.c_str());
+ if (isNewerThan(fullName, fullOut))
+ doit = true;
+ }
+ //trace("Needs it:%d", doit);
+ if (!doit)
+ {
+ return true;
+ }
+
+ String cmd = "dllwrap";
+ cmd.append(" -o ");
+ cmd.append(fullOut);
+ if (defFileName.size()>0)
+ {
+ cmd.append(" --def ");
+ cmd.append(defFileName);
+ cmd.append(" ");
+ }
+ if (impFileName.size()>0)
+ {
+ cmd.append(" --implib ");
+ cmd.append(impFileName);
+ cmd.append(" ");
+ }
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
+ {
+ String fname;
+ if (fileSetDir.size()>0)
+ {
+ fname.append(fileSetDir);
+ fname.append("/");
+ }
+ fname.append(fileSet[i]);
+ String fullName = parent.resolve(fname);
+
+ cmd.append(" ");
+ cmd.append(fullName);
+ }
+ cmd.append(" ");
+ cmd.append(libs);
+
+ String outString, errString;
+ if (!executeCommand(cmd.c_str(), "", outString, errString))
+ {
+ error("<sharedlib> problem: %s", errString.c_str());
+ return false;
}
return true;
virtual bool parse(Element *elem)
{
- if (!parent.getAttribute(elem, "todir", toDirName))
+ if (!parent.getAttribute(elem, "file", fileName))
+ return false;
+ if (!parent.getAttribute(elem, "import", impFileName))
+ return false;
+ if (!parent.getAttribute(elem, "def", defFileName))
return false;
std::vector<Element *> children = elem->getChildren();
String tagName = child->getName();
if (tagName == "fileset")
{
- if (!getFileSet(child, parent, fileSetDir, fileSet))
+ if (!parseFileSet(child, parent, fileSet))
+ return false;
+ }
+ else if (tagName == "libs")
+ {
+ if (!parent.getValue(child, libs))
return false;
+ libs = strip(libs);
}
}
return true;
private:
String command;
- String toDirName;
- String fileSetDir;
- std::vector<String> fileSet;
+ String fileName;
+ String defFileName;
+ String impFileName;
+ FileSet fileSet;
+ String libs;
};
-
-
-
/**
- * Process an archive to allow random access
+ * Run the "ar" command to archive .o's into a .a
*/
-class TaskRanlib : public Task
+class TaskStaticLib : public Task
{
public:
- TaskRanlib(MakeBase &par) : Task(par)
- { type = TASK_RANLIB; name = "ranlib"; }
+ TaskStaticLib(MakeBase &par) : Task(par)
+ {
+ type = TASK_STATICLIB; name = "staticlib";
+ command = "ar crv";
+ }
- virtual ~TaskRanlib()
+ virtual ~TaskStaticLib()
{}
virtual bool execute()
{
- String fullName = parent.resolve(fileName);
- //trace("fullDir:%s", fullDir.c_str());
- String cmd = "ranlib ";
- cmd.append(fullName);
- String outbuf, errbuf;
- if (!executeCommand(cmd, "", outbuf, errbuf))
+ //trace("###########HERE %d", fileSet.size());
+ bool doit = false;
+
+ String fullOut = parent.resolve(fileName);
+ //trace("ar fullout: %s", fullOut.c_str());
+
+ if (!listFiles(parent, fileSet))
return false;
- return true;
- }
+ String fileSetDir = fileSet.getDirectory();
- virtual bool parse(Element *elem)
- {
- if (!parent.getAttribute(elem, "file", fileName))
- return false;
- if (fileName.size() == 0)
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
{
- error("<ranlib> requires 'file=\"fileNname\"' attribute");
- return false;
+ String fname;
+ if (fileSetDir.size()>0)
+ {
+ fname.append(fileSetDir);
+ fname.append("/");
+ }
+ fname.append(fileSet[i]);
+ String fullName = parent.resolve(fname);
+ //trace("ar : %s/%s", fullOut.c_str(), fullName.c_str());
+ if (isNewerThan(fullName, fullOut))
+ doit = true;
}
- return true;
- }
-
-private:
-
- String fileName;
-};
-
-
-
-/**
- * Run the "ar" command to archive .o's into a .a
- */
-class TaskRC : public Task
-{
-public:
-
- TaskRC(MakeBase &par) : Task(par)
- {
- type = TASK_RC; name = "rc";
- command = "windres -o";
- }
-
- virtual ~TaskRC()
- {}
-
- virtual bool execute()
- {
- String fullFile = parent.resolve(fileName);
- String fullOut = parent.resolve(outName);
- if (!isNewerThan(fullFile, fullOut))
+ //trace("Needs it:%d", doit);
+ if (!doit)
+ {
return true;
+ }
+
String cmd = command;
cmd.append(" ");
cmd.append(fullOut);
- cmd.append(" ");
- cmd.append(flags);
- cmd.append(" ");
- cmd.append(fullFile);
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
+ {
+ String fname;
+ if (fileSetDir.size()>0)
+ {
+ fname.append(fileSetDir);
+ fname.append("/");
+ }
+ fname.append(fileSet[i]);
+ String fullName = parent.resolve(fname);
+
+ cmd.append(" ");
+ cmd.append(fullName);
+ }
String outString, errString;
if (!executeCommand(cmd.c_str(), "", outString, errString))
{
- error("RC problem: %s", errString.c_str());
+ error("<staticlib> problem: %s", errString.c_str());
return false;
}
+
return true;
}
virtual bool parse(Element *elem)
{
- if (!parent.getAttribute(elem, "command", command))
+ String s;
+ if (!parent.getAttribute(elem, "command", s))
return false;
+ if (s.size()>0)
+ command = s;
if (!parent.getAttribute(elem, "file", fileName))
return false;
- if (!parent.getAttribute(elem, "out", outName))
- return false;
+
std::vector<Element *> children = elem->getChildren();
for (unsigned int i=0 ; i<children.size() ; i++)
{
Element *child = children[i];
String tagName = child->getName();
- if (tagName == "flags")
+ if (tagName == "fileset")
{
- if (!parent.getValue(child, flags))
+ if (!parseFileSet(child, parent, fileSet))
return false;
}
}
private:
String command;
- String flags;
String fileName;
- String outName;
+ FileSet fileSet;
};
-
/**
* Strip an executable
*/
{
String fullName = parent.resolve(fileName);
//trace("fullDir:%s", fullDir.c_str());
- String cmd = "strip ";
- cmd.append(fullName);
-
+ String cmd;
String outbuf, errbuf;
+
+ if (symFileName.size()>0)
+ {
+ String symFullName = parent.resolve(symFileName);
+ cmd = "objcopy --only-keep-debug ";
+ cmd.append(getNativePath(fullName));
+ cmd.append(" ");
+ cmd.append(getNativePath(symFullName));
+ if (!executeCommand(cmd, "", outbuf, errbuf))
+ {
+ error("<strip> symbol file failed : %s", errbuf.c_str());
+ return false;
+ }
+ }
+
+ cmd = "strip ";
+ cmd.append(getNativePath(fullName));
if (!executeCommand(cmd, "", outbuf, errbuf))
+ {
+ error("<strip> failed : %s", errbuf.c_str());
return false;
+ }
return true;
}
{
if (!parent.getAttribute(elem, "file", fileName))
return false;
+ if (!parent.getAttribute(elem, "symfile", symFileName))
+ return false;
if (fileName.size() == 0)
{
- error("<strip> requires 'file=\"fileNname\"' attribute");
+ error("<strip> requires 'file=\"fileName\"' attribute");
return false;
}
return true;
private:
String fileName;
+ String symFileName;
};
virtual bool parse(Element *elem)
{
- trace("tstamp parse");
+ //trace("tstamp parse");
return true;
}
};
String tagName = elem->getName();
//trace("task:%s", tagName.c_str());
Task *task = NULL;
- if (tagName == "ar")
- task = new TaskAr(parent);
- else if (tagName == "cc")
+ if (tagName == "cc")
task = new TaskCC(parent);
else if (tagName == "copy")
task = new TaskCopy(parent);
task = new TaskRanlib(parent);
else if (tagName == "rc")
task = new TaskRC(parent);
+ else if (tagName == "sharedlib")
+ task = new TaskSharedLib(parent);
+ else if (tagName == "staticlib")
+ task = new TaskStaticLib(parent);
else if (tagName == "strip")
task = new TaskStrip(parent);
else if (tagName == "tstamp")
/**
*
*/
- bool run();
+ virtual String version()
+ { return "BuildTool v0.6.1, 2006 Bob Jamison"; }
+
+ /**
+ * Overload a <property>
+ */
+ virtual bool specifyProperty(const String &name,
+ const String &value);
+
+ /**
+ *
+ */
+ virtual bool run();
/**
*
*/
- bool run(const String &target);
+ virtual bool run(const String &target);
*
*/
bool executeTarget(Target &target,
- std::set<String> &targetsCompleted);
+ std::set<String> &targetsCompleted);
/**
*
*/
bool parsePropertyFile(const String &fileName,
- const String &prefix);
+ const String &prefix);
/**
*
std::map<String, Target> targets;
std::vector<Task *> allTasks;
-
+
+ std::map<String, String> specifiedProperties;
};
}
std::map<String, Target>::iterator iter =
- targets.find(currentTarget);
+ targets.find(currentTarget);
if (iter == targets.end())
{
error("Initial target '%s' not found",
- currentTarget.c_str());
+ currentTarget.c_str());
return false;
}
if (p2 <= p)
{
error("property file %s, line %d: expected keyword",
- fileName.c_str(), linenr);
- return false;
- }
- if (prefix.size() > 0)
- {
- key.insert(0, prefix);
- }
+ fileName.c_str(), linenr);
+ return false;
+ }
+ if (prefix.size() > 0)
+ {
+ key.insert(0, prefix);
+ }
//skip whitespace
- for (p=p2 ; p<len ; p++)
- if (!isspace(s[p]))
- break;
+ for (p=p2 ; p<len ; p++)
+ if (!isspace(s[p]))
+ break;
if (p>=len || s[p]!='=')
{
error("property file %s, line %d: expected '='",
- fileName.c_str(), linenr);
+ fileName.c_str(), linenr);
return false;
}
p++;
//skip whitespace
- for ( ; p<len ; p++)
- if (!isspace(s[p]))
- break;
+ for ( ; p<len ; p++)
+ if (!isspace(s[p]))
+ break;
/* This way expects a word after the =
- p2 = getword(p, s, val);
+ p2 = getword(p, s, val);
if (p2 <= p)
{
error("property file %s, line %d: expected value",
- fileName.c_str(), linenr);
- return false;
- }
- */
+ fileName.c_str(), linenr);
+ return false;
+ }
+ */
// This way gets the rest of the line after the =
- if (p>=len)
+ if (p>=len)
{
error("property file %s, line %d: expected value",
- fileName.c_str(), linenr);
- return false;
- }
+ fileName.c_str(), linenr);
+ return false;
+ }
val = s.substr(p);
- if (key.size()==0 || val.size()==0)
- continue;
+ if (key.size()==0)
+ continue;
+ //allow property to be set, even if val=""
//trace("key:'%s' val:'%s'", key.c_str(), val.c_str());
- properties[key] = val;
+ //See if we wanted to overload this property
+ std::map<String, String>::iterator iter =
+ specifiedProperties.find(key);
+ if (iter!=specifiedProperties.end())
+ {
+ val = iter->second;
+ status("overloading property '%s' = '%s'",
+ key.c_str(), val.c_str());
+ }
+ properties[key] = val;
}
fclose(f);
return true;
if (attrName == "name")
{
String val;
- if (!getAttribute(elem, "value", val))
- return false;
+ if (!getAttribute(elem, "value", val))
+ return false;
if (val.size() > 0)
{
properties[attrVal] = val;
- continue;
}
- if (!getAttribute(elem, "location", val))
- return false;
- if (val.size() > 0)
+ else
{
- //TODO: process a path relative to build.xml
+ if (!getAttribute(elem, "location", val))
+ return false;
+ //let the property exist, even if not defined
+ properties[attrVal] = val;
+ }
+ //See if we wanted to overload this property
+ std::map<String, String>::iterator iter =
+ specifiedProperties.find(attrVal);
+ if (iter != specifiedProperties.end())
+ {
+ val = iter->second;
+ status("overloading property '%s' = '%s'",
+ attrVal.c_str(), val.c_str());
properties[attrVal] = val;
- continue;
}
}
else if (attrName == "file")
{
String prefix;
- if (!getAttribute(elem, "prefix", prefix))
- return false;
+ if (!getAttribute(elem, "prefix", prefix))
+ return false;
if (prefix.size() > 0)
{
if (prefix[prefix.size()-1] != '.')
*/
bool Make::parseFile()
{
- status("######## PARSE");
+ status("######## PARSE : %s", uri.getPath().c_str());
Parser parser;
Element *root = parser.parseFile(uri.getNativePath());
if (!root)
{
error("Could not open %s for reading",
- uri.getNativePath().c_str());
+ uri.getNativePath().c_str());
return false;
}
}
+/**
+ * Overload a <property>
+ */
+bool Make::specifyProperty(const String &name, const String &value)
+{
+ if (specifiedProperties.find(name) != specifiedProperties.end())
+ {
+ error("Property %s already specified", name.c_str());
+ return false;
+ }
+ specifiedProperties[name] = value;
+ return true;
+}
+
+
+
/**
*
*/
{
if (!parseFile())
return false;
+
if (!execute())
return false;
+
return true;
}
+
+
+/**
+ * Get a formatted MM:SS.sss time elapsed string
+ */
+static String
+timeDiffString(struct timeval &x, struct timeval &y)
+{
+ long microsX = x.tv_usec;
+ long secondsX = x.tv_sec;
+ long microsY = y.tv_usec;
+ long secondsY = y.tv_sec;
+ if (microsX < microsY)
+ {
+ microsX += 1000000;
+ secondsX -= 1;
+ }
+
+ int seconds = (int)(secondsX - secondsY);
+ int millis = (int)((microsX - microsY)/1000);
+
+ int minutes = seconds/60;
+ seconds -= minutes*60;
+ char buf[80];
+ snprintf(buf, 79, "%dm %d.%03ds", minutes, seconds, millis);
+ String ret = buf;
+ return ret;
+
+}
+
/**
*
*/
bool Make::run(const String &target)
{
- status("##################################");
- status("# BuildTool");
- status("# version 0.2");
- status("##################################");
+ status("####################################################");
+ status("# %s", version().c_str());
+ status("####################################################");
+ struct timeval timeStart, timeEnd;
+ ::gettimeofday(&timeStart, NULL);
specifiedTarget = target;
if (!run())
return false;
- status("##################################");
- status("# BuildTool Completed");
- status("##################################");
+ ::gettimeofday(&timeEnd, NULL);
+ String timeStr = timeDiffString(timeEnd, timeStart);
+ status("####################################################");
+ status("# BuildTool Completed : %s", timeStr.c_str());
+ status("####################################################");
return true;
}
//# M A I N
//########################################################################
+typedef buildtool::String String;
+
/**
* Format an error message in printf() style
*/
}
+static bool parseProperty(const String &s, String &name, String &val)
+{
+ int len = s.size();
+ int i;
+ for (i=0 ; i<len ; i++)
+ {
+ char ch = s[i];
+ if (ch == '=')
+ break;
+ name.push_back(ch);
+ }
+ if (i>=len || s[i]!='=')
+ {
+ error("property requires -Dname=value");
+ return false;
+ }
+ i++;
+ for ( ; i<len ; i++)
+ {
+ char ch = s[i];
+ val.push_back(ch);
+ }
+ return true;
+}
+
+
/**
* Compare a buffer with a key, for the length of the key
*/
-static bool sequ(const buildtool::String &buf, char *key)
+static bool sequ(const String &buf, char *key)
{
- for (int i=0 ; key[i] ; i++)
+ int len = buf.size();
+ for (int i=0 ; key[i] && i<len ; i++)
{
if (key[i] != buf[i])
return false;
return true;
}
+static void usage(int argc, char **argv)
+{
+ printf("usage:\n");
+ printf(" %s [options] [target]\n", argv[0]);
+ 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");
+}
+
+
+
+
/**
* Parse the command-line args, get our options,
* and run this thing
return false;
}
- buildtool::String buildFile;
- buildtool::String target;
+ buildtool::Make make;
+
+ String target;
//char *progName = argv[0];
for (int i=1 ; i<argc ; i++)
{
- buildtool::String arg = argv[i];
- if (sequ(arg, "--"))
+ String arg = argv[i];
+ if (arg.size()>1 && arg[0]=='-')
{
- if (sequ(arg, "--file=") && arg.size()>7)
+ if (arg == "-h" || arg == "-help")
+ {
+ usage(argc,argv);
+ return true;
+ }
+ else if (arg == "-version")
{
- buildFile = arg.substr(7, arg.size()-7);
+ printf("%s", make.version().c_str());
+ return true;
+ }
+ else if (arg == "-f" || arg == "-file")
+ {
+ if (i>=argc)
+ {
+ usage(argc, argv);
+ return false;
+ }
+ i++; //eat option
+ make.setURI(argv[i]);
+ }
+ else if (arg.size()>2 && sequ(arg, "-D"))
+ {
+ String s = arg.substr(2, s.size());
+ String name, value;
+ if (!parseProperty(s, name, value))
+ {
+ usage(argc, argv);
+ return false;
+ }
+ if (!make.specifyProperty(name, value))
+ return false;
}
else
{
return false;
}
}
- else if (sequ(arg, "-"))
+ else
{
- for (unsigned int p=1 ; p<arg.size() ; p++)
+ if (target.size()>0)
{
- int ch = arg[p];
- if (0)//put options here
- {
- }
- else
- {
- error("Unknown option '%c'", ch);
- return false;
- }
+ error("only one initial target");
+ usage(argc, argv);
+ return false;
}
- }
- else
- {
target = arg;
}
}
//We have the options. Now execute them
- buildtool::Make make;
- if (buildFile.size() > 0)
- {
- make.setURI(buildFile);
- }
if (!make.run(target))
return false;
if (!deptool.generateDependencies("build.dep"))
return false;
std::vector<buildtool::DepRec> res =
- deptool.loadDepFile("build.dep");
- if (res.size() == 0)
+ deptool.loadDepFile("build.dep");
+ if (res.size() == 0)
return false;
return true;
}
{
buildtool::Make make;
buildtool::String out, err;
- bool ret = make.executeCommand("gcc xx.cpp", "", out, err);
+ bool ret = make.executeCommand("gcc xx.cpp", "", out, err);
printf("Popen test:%d '%s' '%s'\n", ret, out.c_str(), err.c_str());
return true;
}