From 1df3a36f6d4cb38963d36fc74aa47990fd055859 Mon Sep 17 00:00:00 2001 From: ishmal Date: Sat, 18 Nov 2006 00:54:53 +0000 Subject: [PATCH] Added regex. Greatly improved scanning. --- build.xml | 22 +- buildtool.cpp | 1107 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 1054 insertions(+), 75 deletions(-) diff --git a/build.xml b/build.xml index 79b3bf42c..76ab1f66d 100644 --- a/build.xml +++ b/build.xml @@ -211,11 +211,11 @@ - - - - - + + + + + -L${gtk}/lib @@ -288,7 +288,11 @@ - + + + + + @@ -297,7 +301,11 @@ - + + + + + diff --git a/buildtool.cpp b/buildtool.cpp index e3efeff5e..97c5a179d 100644 --- a/buildtool.cpp +++ b/buildtool.cpp @@ -58,6 +58,748 @@ 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 +#include + +/* see copyright notice in trex.h */ +#include +#include +#include +#include +//#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 + +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 +//######################################################################## +//######################################################################## + + @@ -1912,6 +2654,129 @@ bool URI::parse(const String &str) //######################################################################## //######################################################################## +//######################################################################## +//# F I L E S E T +//######################################################################## +/** + * This is the descriptor for a item + */ +class FileSet +{ +public: + + /** + * + */ + FileSet() + {} + + /** + * + */ + FileSet(const FileSet &other) + { assign(other); } + + /** + * + */ + FileSet &operator=(const FileSet &other) + { assign(other); return *this; } + + /** + * + */ + virtual ~FileSet() + {} + + /** + * + */ + String getDirectory() + { return directory; } + + /** + * + */ + void setDirectory(const String &val) + { directory = val; } + + /** + * + */ + void setFiles(const std::vector &val) + { files = val; } + + /** + * + */ + std::vector getFiles() + { return files; } + + /** + * + */ + void setIncludes(const std::vector &val) + { includes = val; } + + /** + * + */ + std::vector getIncludes() + { return includes; } + + /** + * + */ + void setExcludes(const std::vector &val) + { excludes = val; } + + /** + * + */ + std::vector 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 files; + std::vector includes; + std::vector excludes; +}; + + //######################################################################## @@ -1978,6 +2843,11 @@ protected: */ void trace(char *fmt, ...); + /** + * Check if a given string matches a given regex pattern + */ + bool regexMatch(const String &str, const String &pattern); + /** * */ @@ -2029,18 +2899,21 @@ protected: std::vector &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 &excludes, - std::vector &res); + std::vector &result); + + /** + * Perform a listing for a fileset + */ + bool listFiles(MakeBase &propRef, FileSet &fileSet); /** * Parse a */ - bool getPatternSet(Element *elem, + bool parsePatternSet(Element *elem, MakeBase &propRef, std::vector &includes, std::vector &excludes); @@ -2049,10 +2922,9 @@ protected: * Parse a entry, and determine which files * should be included */ - bool getFileSet(Element *elem, + bool parseFileSet(Element *elem, MakeBase &propRef, - String &dir, - std::vector &result); + FileSet &fileSet); /** * Return this object's property list @@ -2182,6 +3054,40 @@ void MakeBase::trace(char *fmt, ...) } + +/** + * 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 */ @@ -2661,7 +3567,6 @@ bool MakeBase::listDirectories(const String &baseName, bool MakeBase::listFiles(const String &baseDir, const String &dirName, - std::vector &excludes, std::vector &res) { String fullDir = baseDir; @@ -2695,34 +3600,22 @@ bool MakeBase::listFiles(const String &baseDir, 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); @@ -2730,7 +3623,68 @@ bool MakeBase::listFiles(const String &baseDir, } +bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet) +{ + String baseDir = propRef.resolve(fileSet.getDirectory()); + std::vector fileList; + if (!listFiles(baseDir, "", fileList)) + return false; + std::vector includes = fileSet.getIncludes(); + std::vector excludes = fileSet.getExcludes(); + + std::vector incs; + std::vector::iterator iter; + + std::sort(fileList.begin(), fileList.end()); + + //If there are , 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::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 + std::vector res; + for (iter = incs.begin() ; iter != incs.end() ; iter++) + { + String s = *iter; + bool skipme = false; + std::vector::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; +} @@ -2828,7 +3782,7 @@ bool MakeBase::getBool(const String &str, bool &val) /** * Parse a entry */ -bool MakeBase::getPatternSet(Element *elem, +bool MakeBase::parsePatternSet(Element *elem, MakeBase &propRef, std::vector &includes, std::vector &excludes @@ -2867,10 +3821,9 @@ bool MakeBase::getPatternSet(Element *elem, * Parse a entry, and determine which files * should be included */ -bool MakeBase::getFileSet(Element *elem, +bool MakeBase::parseFileSet(Element *elem, MakeBase &propRef, - String &dir, - std::vector &result) + FileSet &fileSet) { String name = elem->getName(); if (name != "fileset") @@ -2884,7 +3837,7 @@ bool MakeBase::getFileSet(Element *elem, std::vector excludes; //A fileset has one implied patternset - if (!getPatternSet(elem, propRef, includes, excludes)) + if (!parsePatternSet(elem, propRef, includes, excludes)) { return false; } @@ -2896,34 +3849,35 @@ bool MakeBase::getFileSet(Element *elem, 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 fileList; if (dir.size() > 0) { String baseDir = propRef.resolve(dir); - if (!listFiles(baseDir, "", excludes, fileList)) + if (!listFiles(baseDir, "", includes, excludes, fileList)) return false; } - - std::vector::iterator iter; - for (iter=includes.begin() ; iter!=includes.end() ; iter++) - { - String fname = *iter; - fileList.push_back(fname); - } - + std::sort(fileList.begin(), fileList.end()); result = fileList; + */ + /* for (unsigned int i=0 ; i::iterator iter; for (iter=attrs.begin() ; iter!=attrs.end() ; iter++) { @@ -3655,7 +4608,7 @@ bool PkgConfig::readFile(const String &fileNameArg) } fclose(f); - trace("####### File:\n%s", buf.c_str()); + //trace("####### File:\n%s", buf.c_str()); if (!parse(buf)) { return false; @@ -4736,6 +5689,9 @@ public: 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 ; igetName(); if (tagName == "fileset") { - if (!getFileSet(child, parent, fileSetDir, fileSet)) + if (!parseFileSet(child, parent, fileSet)) return false; } } @@ -4808,8 +5764,7 @@ private: String command; String fileName; - String fileSetDir; - std::vector fileSet; + FileSet fileSet; }; @@ -4833,7 +5788,7 @@ public: flags = ""; defines = ""; includes = ""; - sourceFiles.clear(); + fileSet.clear(); } virtual ~TaskCC() @@ -4841,9 +5796,12 @@ public: virtual bool execute() { + if (!listFiles(parent, fileSet)) + return false; + DepTool depTool; depTool.setSourceDirectory(source); - depTool.setFileList(sourceFiles); + depTool.setFileList(fileSet.getFiles()); std::vector deps = depTool.getDepFile("build.dep"); String incs; @@ -4991,8 +5949,9 @@ public: } else if (tagName == "fileset") { - if (!getFileSet(child, parent, source, sourceFiles)) + if (!parseFileSet(child, parent, fileSet)) return false; + source = fileSet.getDirectory(); } } @@ -5008,7 +5967,7 @@ protected: String flags; String defines; String includes; - std::vector sourceFiles; + FileSet fileSet; }; @@ -5071,6 +6030,10 @@ public: { if (haveFileSet) { + if (!listFiles(parent, fileSet)) + return false; + String fileSetDir = fileSet.getDirectory(); + int nrFiles = 0; status(" : %s", fileSetDir.c_str()); for (unsigned int i=0 ; igetName(); if (tagName == "fileset") { - if (!getFileSet(child, parent, fileSetDir, fileSet)) + if (!parseFileSet(child, parent, fileSet)) { error("problem getting fileset"); return false; @@ -5232,8 +6195,7 @@ private: int cptype; String fileName; - String fileSetDir; - std::vector fileSet; + FileSet fileSet; String toFileName; String toDirName; bool verbose; @@ -5417,6 +6379,10 @@ public: 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; @@ -5436,6 +6402,8 @@ public: 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; } @@ -5472,7 +6440,7 @@ public: String tagName = child->getName(); if (tagName == "fileset") { - if (!getFileSet(child, parent, fileSetDir, fileSet)) + if (!parseFileSet(child, parent, fileSet)) return false; } else if (tagName == "flags") @@ -5497,8 +6465,7 @@ private: String fileName; String flags; String libs; - String fileSetDir; - std::vector fileSet; + FileSet fileSet; }; @@ -5626,6 +6593,10 @@ public: virtual bool execute() { + if (!listFiles(parent, fileSet)) + return false; + String fileSetDir = fileSet.getDirectory(); + //trace("msgfmt: %d", fileSet.size()); for (unsigned int i=0 ; igetName(); if (tagName == "fileset") { - if (!getFileSet(child, parent, fileSetDir, fileSet)) + if (!parseFileSet(child, parent, fileSet)) return false; } } @@ -5707,8 +6678,7 @@ private: String command; String toDirName; - String fileSetDir; - std::vector fileSet; + FileSet fileSet; }; @@ -5896,7 +6866,7 @@ public: virtual bool parse(Element *elem) { - trace("tstamp parse"); + //trace("tstamp parse"); return true; } }; @@ -6804,7 +7774,8 @@ bool Make::run(const String &target) { status("##################################"); status("# BuildTool"); - status("# version 0.2"); + status("# version 0.3"); + status("# 16 Nov 06"); status("##################################"); specifiedTarget = target; if (!run()) -- 2.30.2