~ubuntu-branches/debian/experimental/inkscape/experimental

« back to all changes in this revision

Viewing changes to buildtool.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-09-09 23:29:02 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080909232902-c50iujhk1w79u8e7
Tags: 0.46-2.1
* Non-maintainer upload.
* Add upstream patch fixing a crash in the open dialog
  in the zh_CN.utf8 locale. Closes: #487623.
  Thanks to Luca Bruno for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Simple build automation tool.
 
3
 *
 
4
 * Authors:
 
5
 *   Bob Jamison
 
6
 *
 
7
 * Copyright (C) 2006-2007 Bob Jamison
 
8
 *
 
9
 *  This library is free software; you can redistribute it and/or
 
10
 *  modify it under the terms of the GNU Lesser General Public
 
11
 *  License as published by the Free Software Foundation; either
 
12
 *  version 2.1 of the License, or (at your option) any later version.
 
13
 *
 
14
 *  This library is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 *  Lesser General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU Lesser General Public
 
20
 *  License along with this library; if not, write to the Free Software
 
21
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
22
 */
 
23
 
 
24
/**
 
25
 * To use this file, compile with:
 
26
 * <pre>
 
27
 * g++ -O3 buildtool.cpp -o btool.exe
 
28
 * (or whatever your compiler might be)
 
29
 * Then
 
30
 * btool
 
31
 * or
 
32
 * btool {target}
 
33
 *
 
34
 * Note: if you are using MinGW, and a not very recent version of it,
 
35
 * gettimeofday() might be missing.  If so, just build this file with
 
36
 * this command:
 
37
 * g++ -O3 -DNEED_GETTIMEOFDAY buildtool.cpp -o btool.exe
 
38
 *
 
39
 */
 
40
 
 
41
#define BUILDTOOL_VERSION  "BuildTool v0.7.4, 2007 Bob Jamison"
 
42
 
 
43
#include <stdio.h>
 
44
#include <fcntl.h>
 
45
#include <unistd.h>
 
46
#include <stdarg.h>
 
47
#include <sys/stat.h>
 
48
#include <time.h>
 
49
#include <sys/time.h>
 
50
#include <utime.h>
 
51
#include <dirent.h>
 
52
 
 
53
#include <string>
 
54
#include <map>
 
55
#include <set>
 
56
#include <vector>
 
57
 
 
58
#ifdef __WIN32__
 
59
#include <windows.h>
 
60
#endif
 
61
 
 
62
 
 
63
#include <errno.h>
 
64
 
 
65
 
 
66
//########################################################################
 
67
//# Definition of gettimeofday() for those who don't have it
 
68
//########################################################################
 
69
#ifdef NEED_GETTIMEOFDAY
 
70
#include <sys/timeb.h>
 
71
 
 
72
struct timezone {
 
73
      int tz_minuteswest; /* minutes west of Greenwich */
 
74
      int tz_dsttime;     /* type of dst correction */
 
75
    };
 
76
 
 
77
static int gettimeofday (struct timeval *tv, struct timezone *tz)
 
78
{
 
79
   struct _timeb tb;
 
80
 
 
81
   if (!tv)
 
82
      return (-1);
 
83
 
 
84
    _ftime (&tb);
 
85
    tv->tv_sec  = tb.time;
 
86
    tv->tv_usec = tb.millitm * 1000 + 500;
 
87
    if (tz)
 
88
        {
 
89
        tz->tz_minuteswest = -60 * _timezone;
 
90
        tz->tz_dsttime = _daylight;
 
91
        }
 
92
    return 0;
 
93
}
 
94
 
 
95
#endif
 
96
 
 
97
 
 
98
 
 
99
 
 
100
 
 
101
 
 
102
 
 
103
namespace buildtool
 
104
{
 
105
 
 
106
 
 
107
 
 
108
 
 
109
//########################################################################
 
110
//########################################################################
 
111
//##  R E G E X P
 
112
//########################################################################
 
113
//########################################################################
 
114
 
 
115
/**
 
116
 * This is the T-Rex regular expression library, which we
 
117
 * gratefully acknowledge.  It's clean code and small size allow
 
118
 * us to embed it in BuildTool without adding a dependency
 
119
 *
 
120
 */    
 
121
 
 
122
//begin trex.h
 
123
 
 
124
#ifndef _TREX_H_
 
125
#define _TREX_H_
 
126
/***************************************************************
 
127
    T-Rex a tiny regular expression library
 
128
 
 
129
    Copyright (C) 2003-2006 Alberto Demichelis
 
130
 
 
131
    This software is provided 'as-is', without any express 
 
132
    or implied warranty. In no event will the authors be held 
 
133
    liable for any damages arising from the use of this software.
 
134
 
 
135
    Permission is granted to anyone to use this software for 
 
136
    any purpose, including commercial applications, and to alter
 
137
    it and redistribute it freely, subject to the following restrictions:
 
138
 
 
139
        1. The origin of this software must not be misrepresented;
 
140
        you must not claim that you wrote the original software.
 
141
        If you use this software in a product, an acknowledgment
 
142
        in the product documentation would be appreciated but
 
143
        is not required.
 
144
 
 
145
        2. Altered source versions must be plainly marked as such,
 
146
        and must not be misrepresented as being the original software.
 
147
 
 
148
        3. This notice may not be removed or altered from any
 
149
        source distribution.
 
150
 
 
151
****************************************************************/
 
152
 
 
153
#ifdef _UNICODE
 
154
#define TRexChar unsigned short
 
155
#define MAX_CHAR 0xFFFF
 
156
#define _TREXC(c) L##c 
 
157
#define trex_strlen wcslen
 
158
#define trex_printf wprintf
 
159
#else
 
160
#define TRexChar char
 
161
#define MAX_CHAR 0xFF
 
162
#define _TREXC(c) (c) 
 
163
#define trex_strlen strlen
 
164
#define trex_printf printf
 
165
#endif
 
166
 
 
167
#ifndef TREX_API
 
168
#define TREX_API extern
 
169
#endif
 
170
 
 
171
#define TRex_True 1
 
172
#define TRex_False 0
 
173
 
 
174
typedef unsigned int TRexBool;
 
175
typedef struct TRex TRex;
 
176
 
 
177
typedef struct {
 
178
    const TRexChar *begin;
 
179
    int len;
 
180
} TRexMatch;
 
181
 
 
182
TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error);
 
183
TREX_API void trex_free(TRex *exp);
 
184
TREX_API TRexBool trex_match(TRex* exp,const TRexChar* text);
 
185
TREX_API TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
 
186
TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end);
 
187
TREX_API int trex_getsubexpcount(TRex* exp);
 
188
TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
 
189
 
 
190
#endif
 
191
 
 
192
//end trex.h
 
193
 
 
194
//start trex.c
 
195
 
 
196
 
 
197
#include <stdio.h>
 
198
#include <string>
 
199
 
 
200
/* see copyright notice in trex.h */
 
201
#include <string.h>
 
202
#include <stdlib.h>
 
203
#include <ctype.h>
 
204
#include <setjmp.h>
 
205
//#include "trex.h"
 
206
 
 
207
#ifdef _UINCODE
 
208
#define scisprint iswprint
 
209
#define scstrlen wcslen
 
210
#define scprintf wprintf
 
211
#define _SC(x) L(x)
 
212
#else
 
213
#define scisprint isprint
 
214
#define scstrlen strlen
 
215
#define scprintf printf
 
216
#define _SC(x) (x)
 
217
#endif
 
218
 
 
219
#ifdef _DEBUG
 
220
#include <stdio.h>
 
221
 
 
222
static const TRexChar *g_nnames[] =
 
223
{
 
224
    _SC("NONE"),_SC("OP_GREEDY"),    _SC("OP_OR"),
 
225
    _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"),    _SC("OP_CLASS"),
 
226
    _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
 
227
    _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
 
228
};
 
229
 
 
230
#endif
 
231
#define OP_GREEDY        (MAX_CHAR+1) // * + ? {n}
 
232
#define OP_OR            (MAX_CHAR+2)
 
233
#define OP_EXPR            (MAX_CHAR+3) //parentesis ()
 
234
#define OP_NOCAPEXPR    (MAX_CHAR+4) //parentesis (?:)
 
235
#define OP_DOT            (MAX_CHAR+5)
 
236
#define OP_CLASS        (MAX_CHAR+6)
 
237
#define OP_CCLASS        (MAX_CHAR+7)
 
238
#define OP_NCLASS        (MAX_CHAR+8) //negates class the [^
 
239
#define OP_RANGE        (MAX_CHAR+9)
 
240
#define OP_CHAR            (MAX_CHAR+10)
 
241
#define OP_EOL            (MAX_CHAR+11)
 
242
#define OP_BOL            (MAX_CHAR+12)
 
243
#define OP_WB            (MAX_CHAR+13)
 
244
 
 
245
#define TREX_SYMBOL_ANY_CHAR ('.')
 
246
#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
 
247
#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
 
248
#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
 
249
#define TREX_SYMBOL_BRANCH ('|')
 
250
#define TREX_SYMBOL_END_OF_STRING ('$')
 
251
#define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
 
252
#define TREX_SYMBOL_ESCAPE_CHAR ('\\')
 
253
 
 
254
 
 
255
typedef int TRexNodeType;
 
256
 
 
257
typedef struct tagTRexNode{
 
258
    TRexNodeType type;
 
259
    int left;
 
260
    int right;
 
261
    int next;
 
262
}TRexNode;
 
263
 
 
264
struct TRex{
 
265
    const TRexChar *_eol;
 
266
    const TRexChar *_bol;
 
267
    const TRexChar *_p;
 
268
    int _first;
 
269
    int _op;
 
270
    TRexNode *_nodes;
 
271
    int _nallocated;
 
272
    int _nsize;
 
273
    int _nsubexpr;
 
274
    TRexMatch *_matches;
 
275
    int _currsubexp;
 
276
    void *_jmpbuf;
 
277
    const TRexChar **_error;
 
278
};
 
279
 
 
280
static int trex_list(TRex *exp);
 
281
 
 
282
static int trex_newnode(TRex *exp, TRexNodeType type)
 
283
{
 
284
    TRexNode n;
 
285
    int newid;
 
286
    n.type = type;
 
287
    n.next = n.right = n.left = -1;
 
288
    if(type == OP_EXPR)
 
289
        n.right = exp->_nsubexpr++;
 
290
    if(exp->_nallocated < (exp->_nsize + 1)) {
 
291
        //int oldsize = exp->_nallocated;
 
292
        exp->_nallocated *= 2;
 
293
        exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
 
294
    }
 
295
    exp->_nodes[exp->_nsize++] = n;
 
296
    newid = exp->_nsize - 1;
 
297
    return (int)newid;
 
298
}
 
299
 
 
300
static void trex_error(TRex *exp,const TRexChar *error)
 
301
{
 
302
    if(exp->_error) *exp->_error = error;
 
303
    longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
 
304
}
 
305
 
 
306
static void trex_expect(TRex *exp, int n){
 
307
    if((*exp->_p) != n) 
 
308
        trex_error(exp, _SC("expected paren"));
 
309
    exp->_p++;
 
310
}
 
311
 
 
312
static TRexChar trex_escapechar(TRex *exp)
 
313
{
 
314
    if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
 
315
        exp->_p++;
 
316
        switch(*exp->_p) {
 
317
        case 'v': exp->_p++; return '\v';
 
318
        case 'n': exp->_p++; return '\n';
 
319
        case 't': exp->_p++; return '\t';
 
320
        case 'r': exp->_p++; return '\r';
 
321
        case 'f': exp->_p++; return '\f';
 
322
        default: return (*exp->_p++);
 
323
        }
 
324
    } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));
 
325
    return (*exp->_p++);
 
326
}
 
327
 
 
328
static int trex_charclass(TRex *exp,int classid)
 
329
{
 
330
    int n = trex_newnode(exp,OP_CCLASS);
 
331
    exp->_nodes[n].left = classid;
 
332
    return n;
 
333
}
 
334
 
 
335
static int trex_charnode(TRex *exp,TRexBool isclass)
 
336
{
 
337
    TRexChar t;
 
338
    if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
 
339
        exp->_p++;
 
340
        switch(*exp->_p) {
 
341
            case 'n': exp->_p++; return trex_newnode(exp,'\n');
 
342
            case 't': exp->_p++; return trex_newnode(exp,'\t');
 
343
            case 'r': exp->_p++; return trex_newnode(exp,'\r');
 
344
            case 'f': exp->_p++; return trex_newnode(exp,'\f');
 
345
            case 'v': exp->_p++; return trex_newnode(exp,'\v');
 
346
            case 'a': case 'A': case 'w': case 'W': case 's': case 'S': 
 
347
            case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': 
 
348
            case 'p': case 'P': case 'l': case 'u': 
 
349
                {
 
350
                t = *exp->_p; exp->_p++; 
 
351
                return trex_charclass(exp,t);
 
352
                }
 
353
            case 'b': 
 
354
            case 'B':
 
355
                if(!isclass) {
 
356
                    int node = trex_newnode(exp,OP_WB);
 
357
                    exp->_nodes[node].left = *exp->_p;
 
358
                    exp->_p++; 
 
359
                    return node;
 
360
                } //else default
 
361
            default: 
 
362
                t = *exp->_p; exp->_p++; 
 
363
                return trex_newnode(exp,t);
 
364
        }
 
365
    }
 
366
    else if(!scisprint(*exp->_p)) {
 
367
        
 
368
        trex_error(exp,_SC("letter expected"));
 
369
    }
 
370
    t = *exp->_p; exp->_p++; 
 
371
    return trex_newnode(exp,t);
 
372
}
 
373
static int trex_class(TRex *exp)
 
374
{
 
375
    int ret = -1;
 
376
    int first = -1,chain;
 
377
    if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
 
378
        ret = trex_newnode(exp,OP_NCLASS);
 
379
        exp->_p++;
 
380
    }else ret = trex_newnode(exp,OP_CLASS);
 
381
    
 
382
    if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
 
383
    chain = ret;
 
384
    while(*exp->_p != ']' && exp->_p != exp->_eol) {
 
385
        if(*exp->_p == '-' && first != -1){ 
 
386
            int r,t;
 
387
            if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
 
388
            r = trex_newnode(exp,OP_RANGE);
 
389
            if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
 
390
            if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
 
391
            exp->_nodes[r].left = exp->_nodes[first].type;
 
392
            t = trex_escapechar(exp);
 
393
            exp->_nodes[r].right = t;
 
394
            exp->_nodes[chain].next = r;
 
395
            chain = r;
 
396
            first = -1;
 
397
        }
 
398
        else{
 
399
            if(first!=-1){
 
400
                int c = first;
 
401
                exp->_nodes[chain].next = c;
 
402
                chain = c;
 
403
                first = trex_charnode(exp,TRex_True);
 
404
            }
 
405
            else{
 
406
                first = trex_charnode(exp,TRex_True);
 
407
            }
 
408
        }
 
409
    }
 
410
    if(first!=-1){
 
411
        int c = first;
 
412
        exp->_nodes[chain].next = c;
 
413
        chain = c;
 
414
        first = -1;
 
415
    }
 
416
    /* hack? */
 
417
    exp->_nodes[ret].left = exp->_nodes[ret].next;
 
418
    exp->_nodes[ret].next = -1;
 
419
    return ret;
 
420
}
 
421
 
 
422
static int trex_parsenumber(TRex *exp)
 
423
{
 
424
    int ret = *exp->_p-'0';
 
425
    int positions = 10;
 
426
    exp->_p++;
 
427
    while(isdigit(*exp->_p)) {
 
428
        ret = ret*10+(*exp->_p++-'0');
 
429
        if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
 
430
        positions *= 10;
 
431
    };
 
432
    return ret;
 
433
}
 
434
 
 
435
static int trex_element(TRex *exp)
 
436
{
 
437
    int ret = -1;
 
438
    switch(*exp->_p)
 
439
    {
 
440
    case '(': {
 
441
        int expr,newn;
 
442
        exp->_p++;
 
443
 
 
444
 
 
445
        if(*exp->_p =='?') {
 
446
            exp->_p++;
 
447
            trex_expect(exp,':');
 
448
            expr = trex_newnode(exp,OP_NOCAPEXPR);
 
449
        }
 
450
        else
 
451
            expr = trex_newnode(exp,OP_EXPR);
 
452
        newn = trex_list(exp);
 
453
        exp->_nodes[expr].left = newn;
 
454
        ret = expr;
 
455
        trex_expect(exp,')');
 
456
              }
 
457
              break;
 
458
    case '[':
 
459
        exp->_p++;
 
460
        ret = trex_class(exp);
 
461
        trex_expect(exp,']');
 
462
        break;
 
463
    case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
 
464
    case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
 
465
    default:
 
466
        ret = trex_charnode(exp,TRex_False);
 
467
        break;
 
468
    }
 
469
 
 
470
    {
 
471
        int op;
 
472
        TRexBool isgreedy = TRex_False;
 
473
        unsigned short p0 = 0, p1 = 0;
 
474
        switch(*exp->_p){
 
475
            case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
 
476
            case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
 
477
            case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
 
478
            case '{':
 
479
                exp->_p++;
 
480
                if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
 
481
                p0 = (unsigned short)trex_parsenumber(exp);
 
482
                /*******************************/
 
483
                switch(*exp->_p) {
 
484
            case '}':
 
485
                p1 = p0; exp->_p++;
 
486
                break;
 
487
            case ',':
 
488
                exp->_p++;
 
489
                p1 = 0xFFFF;
 
490
                if(isdigit(*exp->_p)){
 
491
                    p1 = (unsigned short)trex_parsenumber(exp);
 
492
                }
 
493
                trex_expect(exp,'}');
 
494
                break;
 
495
            default:
 
496
                trex_error(exp,_SC(", or } expected"));
 
497
        }
 
498
        /*******************************/
 
499
        isgreedy = TRex_True; 
 
500
        break;
 
501
 
 
502
        }
 
503
        if(isgreedy) {
 
504
            int nnode = trex_newnode(exp,OP_GREEDY);
 
505
            op = OP_GREEDY;
 
506
            exp->_nodes[nnode].left = ret;
 
507
            exp->_nodes[nnode].right = ((p0)<<16)|p1;
 
508
            ret = nnode;
 
509
        }
 
510
    }
 
511
    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')) {
 
512
        int nnode = trex_element(exp);
 
513
        exp->_nodes[ret].next = nnode;
 
514
    }
 
515
 
 
516
    return ret;
 
517
}
 
518
 
 
519
static int trex_list(TRex *exp)
 
520
{
 
521
    int ret=-1,e;
 
522
    if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
 
523
        exp->_p++;
 
524
        ret = trex_newnode(exp,OP_BOL);
 
525
    }
 
526
    e = trex_element(exp);
 
527
    if(ret != -1) {
 
528
        exp->_nodes[ret].next = e;
 
529
    }
 
530
    else ret = e;
 
531
 
 
532
    if(*exp->_p == TREX_SYMBOL_BRANCH) {
 
533
        int temp,tright;
 
534
        exp->_p++;
 
535
        temp = trex_newnode(exp,OP_OR);
 
536
        exp->_nodes[temp].left = ret;
 
537
        tright = trex_list(exp);
 
538
        exp->_nodes[temp].right = tright;
 
539
        ret = temp;
 
540
    }
 
541
    return ret;
 
542
}
 
543
 
 
544
static TRexBool trex_matchcclass(int cclass,TRexChar c)
 
545
{
 
546
    switch(cclass) {
 
547
    case 'a': return isalpha(c)?TRex_True:TRex_False;
 
548
    case 'A': return !isalpha(c)?TRex_True:TRex_False;
 
549
    case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
 
550
    case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
 
551
    case 's': return isspace(c)?TRex_True:TRex_False;
 
552
    case 'S': return !isspace(c)?TRex_True:TRex_False;
 
553
    case 'd': return isdigit(c)?TRex_True:TRex_False;
 
554
    case 'D': return !isdigit(c)?TRex_True:TRex_False;
 
555
    case 'x': return isxdigit(c)?TRex_True:TRex_False;
 
556
    case 'X': return !isxdigit(c)?TRex_True:TRex_False;
 
557
    case 'c': return iscntrl(c)?TRex_True:TRex_False;
 
558
    case 'C': return !iscntrl(c)?TRex_True:TRex_False;
 
559
    case 'p': return ispunct(c)?TRex_True:TRex_False;
 
560
    case 'P': return !ispunct(c)?TRex_True:TRex_False;
 
561
    case 'l': return islower(c)?TRex_True:TRex_False;
 
562
    case 'u': return isupper(c)?TRex_True:TRex_False;
 
563
    }
 
564
    return TRex_False; /*cannot happen*/
 
565
}
 
566
 
 
567
static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
 
568
{
 
569
    do {
 
570
        switch(node->type) {
 
571
            case OP_RANGE:
 
572
                if(c >= node->left && c <= node->right) return TRex_True;
 
573
                break;
 
574
            case OP_CCLASS:
 
575
                if(trex_matchcclass(node->left,c)) return TRex_True;
 
576
                break;
 
577
            default:
 
578
                if(c == node->type)return TRex_True;
 
579
        }
 
580
    } while((node->next != -1) && (node = &exp->_nodes[node->next]));
 
581
    return TRex_False;
 
582
}
 
583
 
 
584
static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
 
585
{
 
586
    
 
587
    TRexNodeType type = node->type;
 
588
    switch(type) {
 
589
    case OP_GREEDY: {
 
590
        //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
 
591
        TRexNode *greedystop = NULL;
 
592
        int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
 
593
        const TRexChar *s=str, *good = str;
 
594
 
 
595
        if(node->next != -1) {
 
596
            greedystop = &exp->_nodes[node->next];
 
597
        }
 
598
        else {
 
599
            greedystop = next;
 
600
        }
 
601
 
 
602
        while((nmaches == 0xFFFF || nmaches < p1)) {
 
603
 
 
604
            const TRexChar *stop;
 
605
            if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
 
606
                break;
 
607
            nmaches++;
 
608
            good=s;
 
609
            if(greedystop) {
 
610
                //checks that 0 matches satisfy the expression(if so skips)
 
611
                //if not would always stop(for instance if is a '?')
 
612
                if(greedystop->type != OP_GREEDY ||
 
613
                (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
 
614
                {
 
615
                    TRexNode *gnext = NULL;
 
616
                    if(greedystop->next != -1) {
 
617
                        gnext = &exp->_nodes[greedystop->next];
 
618
                    }else if(next && next->next != -1){
 
619
                        gnext = &exp->_nodes[next->next];
 
620
                    }
 
621
                    stop = trex_matchnode(exp,greedystop,s,gnext);
 
622
                    if(stop) {
 
623
                        //if satisfied stop it
 
624
                        if(p0 == p1 && p0 == nmaches) break;
 
625
                        else if(nmaches >= p0 && p1 == 0xFFFF) break;
 
626
                        else if(nmaches >= p0 && nmaches <= p1) break;
 
627
                    }
 
628
                }
 
629
            }
 
630
            
 
631
            if(s >= exp->_eol)
 
632
                break;
 
633
        }
 
634
        if(p0 == p1 && p0 == nmaches) return good;
 
635
        else if(nmaches >= p0 && p1 == 0xFFFF) return good;
 
636
        else if(nmaches >= p0 && nmaches <= p1) return good;
 
637
        return NULL;
 
638
    }
 
639
    case OP_OR: {
 
640
            const TRexChar *asd = str;
 
641
            TRexNode *temp=&exp->_nodes[node->left];
 
642
            while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
 
643
                if(temp->next != -1)
 
644
                    temp = &exp->_nodes[temp->next];
 
645
                else
 
646
                    return asd;
 
647
            }
 
648
            asd = str;
 
649
            temp = &exp->_nodes[node->right];
 
650
            while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
 
651
                if(temp->next != -1)
 
652
                    temp = &exp->_nodes[temp->next];
 
653
                else
 
654
                    return asd;
 
655
            }
 
656
            return NULL;
 
657
            break;
 
658
    }
 
659
    case OP_EXPR:
 
660
    case OP_NOCAPEXPR:{
 
661
            TRexNode *n = &exp->_nodes[node->left];
 
662
            const TRexChar *cur = str;
 
663
            int capture = -1;
 
664
            if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
 
665
                capture = exp->_currsubexp;
 
666
                exp->_matches[capture].begin = cur;
 
667
                exp->_currsubexp++;
 
668
            }
 
669
            
 
670
            do {
 
671
                TRexNode *subnext = NULL;
 
672
                if(n->next != -1) {
 
673
                    subnext = &exp->_nodes[n->next];
 
674
                }else {
 
675
                    subnext = next;
 
676
                }
 
677
                if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
 
678
                    if(capture != -1){
 
679
                        exp->_matches[capture].begin = 0;
 
680
                        exp->_matches[capture].len = 0;
 
681
                    }
 
682
                    return NULL;
 
683
                }
 
684
            } while((n->next != -1) && (n = &exp->_nodes[n->next]));
 
685
 
 
686
            if(capture != -1) 
 
687
                exp->_matches[capture].len = cur - exp->_matches[capture].begin;
 
688
            return cur;
 
689
    }                 
 
690
    case OP_WB:
 
691
        if(str == exp->_bol && !isspace(*str)
 
692
         || (str == exp->_eol && !isspace(*(str-1)))
 
693
         || (!isspace(*str) && isspace(*(str+1)))
 
694
         || (isspace(*str) && !isspace(*(str+1))) ) {
 
695
            return (node->left == 'b')?str:NULL;
 
696
        }
 
697
        return (node->left == 'b')?NULL:str;
 
698
    case OP_BOL:
 
699
        if(str == exp->_bol) return str;
 
700
        return NULL;
 
701
    case OP_EOL:
 
702
        if(str == exp->_eol) return str;
 
703
        return NULL;
 
704
    case OP_DOT:{
 
705
        *str++;
 
706
                }
 
707
        return str;
 
708
    case OP_NCLASS:
 
709
    case OP_CLASS:
 
710
        if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
 
711
            *str++;
 
712
            return str;
 
713
        }
 
714
        return NULL;
 
715
    case OP_CCLASS:
 
716
        if(trex_matchcclass(node->left,*str)) {
 
717
            *str++;
 
718
            return str;
 
719
        }
 
720
        return NULL;
 
721
    default: /* char */
 
722
        if(*str != node->type) return NULL;
 
723
        *str++;
 
724
        return str;
 
725
    }
 
726
    return NULL;
 
727
}
 
728
 
 
729
/* public api */
 
730
TRex *trex_compile(const TRexChar *pattern,const TRexChar **error)
 
731
{
 
732
    TRex *exp = (TRex *)malloc(sizeof(TRex));
 
733
    exp->_eol = exp->_bol = NULL;
 
734
    exp->_p = pattern;
 
735
    exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
 
736
    exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
 
737
    exp->_nsize = 0;
 
738
    exp->_matches = 0;
 
739
    exp->_nsubexpr = 0;
 
740
    exp->_first = trex_newnode(exp,OP_EXPR);
 
741
    exp->_error = error;
 
742
    exp->_jmpbuf = malloc(sizeof(jmp_buf));
 
743
    if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
 
744
        int res = trex_list(exp);
 
745
        exp->_nodes[exp->_first].left = res;
 
746
        if(*exp->_p!='\0')
 
747
            trex_error(exp,_SC("unexpected character"));
 
748
#ifdef _DEBUG
 
749
        {
 
750
            int nsize,i;
 
751
            TRexNode *t;
 
752
            nsize = exp->_nsize;
 
753
            t = &exp->_nodes[0];
 
754
            scprintf(_SC("\n"));
 
755
            for(i = 0;i < nsize; i++) {
 
756
                if(exp->_nodes[i].type>MAX_CHAR)
 
757
                    scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
 
758
                else
 
759
                    scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
 
760
                scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
 
761
            }
 
762
            scprintf(_SC("\n"));
 
763
        }
 
764
#endif
 
765
        exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
 
766
        memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
 
767
    }
 
768
    else{
 
769
        trex_free(exp);
 
770
        return NULL;
 
771
    }
 
772
    return exp;
 
773
}
 
774
 
 
775
void trex_free(TRex *exp)
 
776
{
 
777
    if(exp)    {
 
778
        if(exp->_nodes) free(exp->_nodes);
 
779
        if(exp->_jmpbuf) free(exp->_jmpbuf);
 
780
        if(exp->_matches) free(exp->_matches);
 
781
        free(exp);
 
782
    }
 
783
}
 
784
 
 
785
TRexBool trex_match(TRex* exp,const TRexChar* text)
 
786
{
 
787
    const TRexChar* res = NULL;
 
788
    exp->_bol = text;
 
789
    exp->_eol = text + scstrlen(text);
 
790
    exp->_currsubexp = 0;
 
791
    res = trex_matchnode(exp,exp->_nodes,text,NULL);
 
792
    if(res == NULL || res != exp->_eol)
 
793
        return TRex_False;
 
794
    return TRex_True;
 
795
}
 
796
 
 
797
TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
 
798
{
 
799
    const TRexChar *cur = NULL;
 
800
    int node = exp->_first;
 
801
    if(text_begin >= text_end) return TRex_False;
 
802
    exp->_bol = text_begin;
 
803
    exp->_eol = text_end;
 
804
    do {
 
805
        cur = text_begin;
 
806
        while(node != -1) {
 
807
            exp->_currsubexp = 0;
 
808
            cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
 
809
            if(!cur)
 
810
                break;
 
811
            node = exp->_nodes[node].next;
 
812
        }
 
813
        *text_begin++;
 
814
    } while(cur == NULL && text_begin != text_end);
 
815
 
 
816
    if(cur == NULL)
 
817
        return TRex_False;
 
818
 
 
819
    --text_begin;
 
820
 
 
821
    if(out_begin) *out_begin = text_begin;
 
822
    if(out_end) *out_end = cur;
 
823
    return TRex_True;
 
824
}
 
825
 
 
826
TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
 
827
{
 
828
    return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
 
829
}
 
830
 
 
831
int trex_getsubexpcount(TRex* exp)
 
832
{
 
833
    return exp->_nsubexpr;
 
834
}
 
835
 
 
836
TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
 
837
{
 
838
    if( n<0 || n >= exp->_nsubexpr) return TRex_False;
 
839
    *subexp = exp->_matches[n];
 
840
    return TRex_True;
 
841
}
 
842
 
 
843
 
 
844
//########################################################################
 
845
//########################################################################
 
846
//##  E N D    R E G E X P
 
847
//########################################################################
 
848
//########################################################################
 
849
 
 
850
 
 
851
 
 
852
 
 
853
 
 
854
//########################################################################
 
855
//########################################################################
 
856
//##  X M L
 
857
//########################################################################
 
858
//########################################################################
 
859
 
 
860
// Note:  This mini-dom library comes from Pedro, another little project
 
861
// of mine.
 
862
 
 
863
typedef std::string String;
 
864
typedef unsigned int XMLCh;
 
865
 
 
866
 
 
867
class Namespace
 
868
{
 
869
public:
 
870
    Namespace()
 
871
        {}
 
872
 
 
873
    Namespace(const String &prefixArg, const String &namespaceURIArg)
 
874
        {
 
875
        prefix       = prefixArg;
 
876
        namespaceURI = namespaceURIArg;
 
877
        }
 
878
 
 
879
    Namespace(const Namespace &other)
 
880
        {
 
881
        assign(other);
 
882
        }
 
883
 
 
884
    Namespace &operator=(const Namespace &other)
 
885
        {
 
886
        assign(other);
 
887
        return *this;
 
888
        }
 
889
 
 
890
    virtual ~Namespace()
 
891
        {}
 
892
 
 
893
    virtual String getPrefix()
 
894
        { return prefix; }
 
895
 
 
896
    virtual String getNamespaceURI()
 
897
        { return namespaceURI; }
 
898
 
 
899
protected:
 
900
 
 
901
    void assign(const Namespace &other)
 
902
        {
 
903
        prefix       = other.prefix;
 
904
        namespaceURI = other.namespaceURI;
 
905
        }
 
906
 
 
907
    String prefix;
 
908
    String namespaceURI;
 
909
 
 
910
};
 
911
 
 
912
class Attribute
 
913
{
 
914
public:
 
915
    Attribute()
 
916
        {}
 
917
 
 
918
    Attribute(const String &nameArg, const String &valueArg)
 
919
        {
 
920
        name  = nameArg;
 
921
        value = valueArg;
 
922
        }
 
923
 
 
924
    Attribute(const Attribute &other)
 
925
        {
 
926
        assign(other);
 
927
        }
 
928
 
 
929
    Attribute &operator=(const Attribute &other)
 
930
        {
 
931
        assign(other);
 
932
        return *this;
 
933
        }
 
934
 
 
935
    virtual ~Attribute()
 
936
        {}
 
937
 
 
938
    virtual String getName()
 
939
        { return name; }
 
940
 
 
941
    virtual String getValue()
 
942
        { return value; }
 
943
 
 
944
protected:
 
945
 
 
946
    void assign(const Attribute &other)
 
947
        {
 
948
        name  = other.name;
 
949
        value = other.value;
 
950
        }
 
951
 
 
952
    String name;
 
953
    String value;
 
954
 
 
955
};
 
956
 
 
957
 
 
958
class Element
 
959
{
 
960
friend class Parser;
 
961
 
 
962
public:
 
963
    Element()
 
964
        {
 
965
        init();
 
966
        }
 
967
 
 
968
    Element(const String &nameArg)
 
969
        {
 
970
        init();
 
971
        name   = nameArg;
 
972
        }
 
973
 
 
974
    Element(const String &nameArg, const String &valueArg)
 
975
        {
 
976
        init();
 
977
        name   = nameArg;
 
978
        value  = valueArg;
 
979
        }
 
980
 
 
981
    Element(const Element &other)
 
982
        {
 
983
        assign(other);
 
984
        }
 
985
 
 
986
    Element &operator=(const Element &other)
 
987
        {
 
988
        assign(other);
 
989
        return *this;
 
990
        }
 
991
 
 
992
    virtual Element *clone();
 
993
 
 
994
    virtual ~Element()
 
995
        {
 
996
        for (unsigned int i=0 ; i<children.size() ; i++)
 
997
            delete children[i];
 
998
        }
 
999
 
 
1000
    virtual String getName()
 
1001
        { return name; }
 
1002
 
 
1003
    virtual String getValue()
 
1004
        { return value; }
 
1005
 
 
1006
    Element *getParent()
 
1007
        { return parent; }
 
1008
 
 
1009
    std::vector<Element *> getChildren()
 
1010
        { return children; }
 
1011
 
 
1012
    std::vector<Element *> findElements(const String &name);
 
1013
 
 
1014
    String getAttribute(const String &name);
 
1015
 
 
1016
    std::vector<Attribute> &getAttributes()
 
1017
        { return attributes; } 
 
1018
 
 
1019
    String getTagAttribute(const String &tagName, const String &attrName);
 
1020
 
 
1021
    String getTagValue(const String &tagName);
 
1022
 
 
1023
    void addChild(Element *child);
 
1024
 
 
1025
    void addAttribute(const String &name, const String &value);
 
1026
 
 
1027
    void addNamespace(const String &prefix, const String &namespaceURI);
 
1028
 
 
1029
 
 
1030
    /**
 
1031
     * Prettyprint an XML tree to an output stream.  Elements are indented
 
1032
     * according to element hierarchy.
 
1033
     * @param f a stream to receive the output
 
1034
     * @param elem the element to output
 
1035
     */
 
1036
    void writeIndented(FILE *f);
 
1037
 
 
1038
    /**
 
1039
     * Prettyprint an XML tree to standard output.  This is the equivalent of
 
1040
     * writeIndented(stdout).
 
1041
     * @param elem the element to output
 
1042
     */
 
1043
    void print();
 
1044
    
 
1045
    int getLine()
 
1046
        { return line; }
 
1047
 
 
1048
protected:
 
1049
 
 
1050
    void init()
 
1051
        {
 
1052
        parent = NULL;
 
1053
        line   = 0;
 
1054
        }
 
1055
 
 
1056
    void assign(const Element &other)
 
1057
        {
 
1058
        parent     = other.parent;
 
1059
        children   = other.children;
 
1060
        attributes = other.attributes;
 
1061
        namespaces = other.namespaces;
 
1062
        name       = other.name;
 
1063
        value      = other.value;
 
1064
        line       = other.line;
 
1065
        }
 
1066
 
 
1067
    void findElementsRecursive(std::vector<Element *>&res, const String &name);
 
1068
 
 
1069
    void writeIndentedRecursive(FILE *f, int indent);
 
1070
 
 
1071
    Element *parent;
 
1072
 
 
1073
    std::vector<Element *>children;
 
1074
 
 
1075
    std::vector<Attribute> attributes;
 
1076
    std::vector<Namespace> namespaces;
 
1077
 
 
1078
    String name;
 
1079
    String value;
 
1080
    
 
1081
    int line;
 
1082
};
 
1083
 
 
1084
 
 
1085
 
 
1086
 
 
1087
 
 
1088
class Parser
 
1089
{
 
1090
public:
 
1091
    /**
 
1092
     * Constructor
 
1093
     */
 
1094
    Parser()
 
1095
        { init(); }
 
1096
 
 
1097
    virtual ~Parser()
 
1098
        {}
 
1099
 
 
1100
    /**
 
1101
     * Parse XML in a char buffer.
 
1102
     * @param buf a character buffer to parse
 
1103
     * @param pos position to start parsing
 
1104
     * @param len number of chars, from pos, to parse.
 
1105
     * @return a pointer to the root of the XML document;
 
1106
     */
 
1107
    Element *parse(const char *buf,int pos,int len);
 
1108
 
 
1109
    /**
 
1110
     * Parse XML in a char buffer.
 
1111
     * @param buf a character buffer to parse
 
1112
     * @param pos position to start parsing
 
1113
     * @param len number of chars, from pos, to parse.
 
1114
     * @return a pointer to the root of the XML document;
 
1115
     */
 
1116
    Element *parse(const String &buf);
 
1117
 
 
1118
    /**
 
1119
     * Parse a named XML file.  The file is loaded like a data file;
 
1120
     * the original format is not preserved.
 
1121
     * @param fileName the name of the file to read
 
1122
     * @return a pointer to the root of the XML document;
 
1123
     */
 
1124
    Element *parseFile(const String &fileName);
 
1125
 
 
1126
    /**
 
1127
     * Utility method to preprocess a string for XML
 
1128
     * output, escaping its entities.
 
1129
     * @param str the string to encode
 
1130
     */
 
1131
    static String encode(const String &str);
 
1132
 
 
1133
    /**
 
1134
     *  Removes whitespace from beginning and end of a string
 
1135
     */
 
1136
    String trim(const String &s);
 
1137
 
 
1138
private:
 
1139
 
 
1140
    void init()
 
1141
        {
 
1142
        keepGoing       = true;
 
1143
        currentNode     = NULL;
 
1144
        parselen        = 0;
 
1145
        parsebuf        = NULL;
 
1146
        currentPosition = 0;
 
1147
        }
 
1148
 
 
1149
    int countLines(int begin, int end);
 
1150
 
 
1151
    void getLineAndColumn(int pos, int *lineNr, int *colNr);
 
1152
 
 
1153
    void error(const char *fmt, ...);
 
1154
 
 
1155
    int peek(int pos);
 
1156
 
 
1157
    int match(int pos, const char *text);
 
1158
 
 
1159
    int skipwhite(int p);
 
1160
 
 
1161
    int getWord(int p0, String &buf);
 
1162
 
 
1163
    int getQuoted(int p0, String &buf, int do_i_parse);
 
1164
 
 
1165
    int parseVersion(int p0);
 
1166
 
 
1167
    int parseDoctype(int p0);
 
1168
 
 
1169
    int parseElement(int p0, Element *par,int depth);
 
1170
 
 
1171
    Element *parse(XMLCh *buf,int pos,int len);
 
1172
 
 
1173
    bool       keepGoing;
 
1174
    Element    *currentNode;
 
1175
    int        parselen;
 
1176
    XMLCh      *parsebuf;
 
1177
    String     cdatabuf;
 
1178
    int        currentPosition;
 
1179
};
 
1180
 
 
1181
 
 
1182
 
 
1183
 
 
1184
//########################################################################
 
1185
//# E L E M E N T
 
1186
//########################################################################
 
1187
 
 
1188
Element *Element::clone()
 
1189
{
 
1190
    Element *elem = new Element(name, value);
 
1191
    elem->parent     = parent;
 
1192
    elem->attributes = attributes;
 
1193
    elem->namespaces = namespaces;
 
1194
    elem->line       = line;
 
1195
 
 
1196
    std::vector<Element *>::iterator iter;
 
1197
    for (iter = children.begin(); iter != children.end() ; iter++)
 
1198
        {
 
1199
        elem->addChild((*iter)->clone());
 
1200
        }
 
1201
    return elem;
 
1202
}
 
1203
 
 
1204
 
 
1205
void Element::findElementsRecursive(std::vector<Element *>&res, const String &name)
 
1206
{
 
1207
    if (getName() == name)
 
1208
        {
 
1209
        res.push_back(this);
 
1210
        }
 
1211
    for (unsigned int i=0; i<children.size() ; i++)
 
1212
        children[i]->findElementsRecursive(res, name);
 
1213
}
 
1214
 
 
1215
std::vector<Element *> Element::findElements(const String &name)
 
1216
{
 
1217
    std::vector<Element *> res;
 
1218
    findElementsRecursive(res, name);
 
1219
    return res;
 
1220
}
 
1221
 
 
1222
String Element::getAttribute(const String &name)
 
1223
{
 
1224
    for (unsigned int i=0 ; i<attributes.size() ; i++)
 
1225
        if (attributes[i].getName() ==name)
 
1226
            return attributes[i].getValue();
 
1227
    return "";
 
1228
}
 
1229
 
 
1230
String Element::getTagAttribute(const String &tagName, const String &attrName)
 
1231
{
 
1232
    std::vector<Element *>elems = findElements(tagName);
 
1233
    if (elems.size() <1)
 
1234
        return "";
 
1235
    String res = elems[0]->getAttribute(attrName);
 
1236
    return res;
 
1237
}
 
1238
 
 
1239
String Element::getTagValue(const String &tagName)
 
1240
{
 
1241
    std::vector<Element *>elems = findElements(tagName);
 
1242
    if (elems.size() <1)
 
1243
        return "";
 
1244
    String res = elems[0]->getValue();
 
1245
    return res;
 
1246
}
 
1247
 
 
1248
void Element::addChild(Element *child)
 
1249
{
 
1250
    if (!child)
 
1251
        return;
 
1252
    child->parent = this;
 
1253
    children.push_back(child);
 
1254
}
 
1255
 
 
1256
 
 
1257
void Element::addAttribute(const String &name, const String &value)
 
1258
{
 
1259
    Attribute attr(name, value);
 
1260
    attributes.push_back(attr);
 
1261
}
 
1262
 
 
1263
void Element::addNamespace(const String &prefix, const String &namespaceURI)
 
1264
{
 
1265
    Namespace ns(prefix, namespaceURI);
 
1266
    namespaces.push_back(ns);
 
1267
}
 
1268
 
 
1269
void Element::writeIndentedRecursive(FILE *f, int indent)
 
1270
{
 
1271
    int i;
 
1272
    if (!f)
 
1273
        return;
 
1274
    //Opening tag, and attributes
 
1275
    for (i=0;i<indent;i++)
 
1276
        fputc(' ',f);
 
1277
    fprintf(f,"<%s",name.c_str());
 
1278
    for (unsigned int i=0 ; i<attributes.size() ; i++)
 
1279
        {
 
1280
        fprintf(f," %s=\"%s\"",
 
1281
              attributes[i].getName().c_str(),
 
1282
              attributes[i].getValue().c_str());
 
1283
        }
 
1284
    for (unsigned int i=0 ; i<namespaces.size() ; i++)
 
1285
        {
 
1286
        fprintf(f," xmlns:%s=\"%s\"",
 
1287
              namespaces[i].getPrefix().c_str(),
 
1288
              namespaces[i].getNamespaceURI().c_str());
 
1289
        }
 
1290
    fprintf(f,">\n");
 
1291
 
 
1292
    //Between the tags
 
1293
    if (value.size() > 0)
 
1294
        {
 
1295
        for (int i=0;i<indent;i++)
 
1296
            fputc(' ', f);
 
1297
        fprintf(f," %s\n", value.c_str());
 
1298
        }
 
1299
 
 
1300
    for (unsigned int i=0 ; i<children.size() ; i++)
 
1301
        children[i]->writeIndentedRecursive(f, indent+2);
 
1302
 
 
1303
    //Closing tag
 
1304
    for (int i=0; i<indent; i++)
 
1305
        fputc(' ',f);
 
1306
    fprintf(f,"</%s>\n", name.c_str());
 
1307
}
 
1308
 
 
1309
void Element::writeIndented(FILE *f)
 
1310
{
 
1311
    writeIndentedRecursive(f, 0);
 
1312
}
 
1313
 
 
1314
void Element::print()
 
1315
{
 
1316
    writeIndented(stdout);
 
1317
}
 
1318
 
 
1319
 
 
1320
//########################################################################
 
1321
//# P A R S E R
 
1322
//########################################################################
 
1323
 
 
1324
 
 
1325
 
 
1326
typedef struct
 
1327
    {
 
1328
    const char *escaped;
 
1329
    char value;
 
1330
    } EntityEntry;
 
1331
 
 
1332
static EntityEntry entities[] =
 
1333
{
 
1334
    { "&amp;" , '&'  },
 
1335
    { "&lt;"  , '<'  },
 
1336
    { "&gt;"  , '>'  },
 
1337
    { "&apos;", '\'' },
 
1338
    { "&quot;", '"'  },
 
1339
    { NULL    , '\0' }
 
1340
};
 
1341
 
 
1342
 
 
1343
 
 
1344
/**
 
1345
 *  Removes whitespace from beginning and end of a string
 
1346
 */
 
1347
String Parser::trim(const String &s)
 
1348
{
 
1349
    if (s.size() < 1)
 
1350
        return s;
 
1351
    
 
1352
    //Find first non-ws char
 
1353
    unsigned int begin = 0;
 
1354
    for ( ; begin < s.size() ; begin++)
 
1355
        {
 
1356
        if (!isspace(s[begin]))
 
1357
            break;
 
1358
        }
 
1359
 
 
1360
    //Find first non-ws char, going in reverse
 
1361
    unsigned int end = s.size() - 1;
 
1362
    for ( ; end > begin ; end--)
 
1363
        {
 
1364
        if (!isspace(s[end]))
 
1365
            break;
 
1366
        }
 
1367
    //trace("begin:%d  end:%d", begin, end);
 
1368
 
 
1369
    String res = s.substr(begin, end-begin+1);
 
1370
    return res;
 
1371
}
 
1372
 
 
1373
 
 
1374
int Parser::countLines(int begin, int end)
 
1375
{
 
1376
    int count = 0;
 
1377
    for (int i=begin ; i<end ; i++)
 
1378
        {
 
1379
        XMLCh ch = parsebuf[i];
 
1380
        if (ch == '\n' || ch == '\r')
 
1381
            count++;
 
1382
        }
 
1383
    return count;
 
1384
}
 
1385
 
 
1386
 
 
1387
void Parser::getLineAndColumn(int pos, int *lineNr, int *colNr)
 
1388
{
 
1389
    int line = 1;
 
1390
    int col  = 1;
 
1391
    for (long i=0 ; i<pos ; i++)
 
1392
        {
 
1393
        XMLCh ch = parsebuf[i];
 
1394
        if (ch == '\n' || ch == '\r')
 
1395
            {
 
1396
            col = 0;
 
1397
            line ++;
 
1398
            }
 
1399
        else
 
1400
            col++;
 
1401
        }
 
1402
    *lineNr = line;
 
1403
    *colNr  = col;
 
1404
 
 
1405
}
 
1406
 
 
1407
 
 
1408
void Parser::error(const char *fmt, ...)
 
1409
{
 
1410
    int lineNr;
 
1411
    int colNr;
 
1412
    getLineAndColumn(currentPosition, &lineNr, &colNr);
 
1413
    va_list args;
 
1414
    fprintf(stderr, "xml error at line %d, column %d:", lineNr, colNr);
 
1415
    va_start(args,fmt);
 
1416
    vfprintf(stderr,fmt,args);
 
1417
    va_end(args) ;
 
1418
    fprintf(stderr, "\n");
 
1419
}
 
1420
 
 
1421
 
 
1422
 
 
1423
int Parser::peek(int pos)
 
1424
{
 
1425
    if (pos >= parselen)
 
1426
        return -1;
 
1427
    currentPosition = pos;
 
1428
    int ch = parsebuf[pos];
 
1429
    //printf("ch:%c\n", ch);
 
1430
    return ch;
 
1431
}
 
1432
 
 
1433
 
 
1434
 
 
1435
String Parser::encode(const String &str)
 
1436
{
 
1437
    String ret;
 
1438
    for (unsigned int i=0 ; i<str.size() ; i++)
 
1439
        {
 
1440
        XMLCh ch = (XMLCh)str[i];
 
1441
        if (ch == '&')
 
1442
            ret.append("&amp;");
 
1443
        else if (ch == '<')
 
1444
            ret.append("&lt;");
 
1445
        else if (ch == '>')
 
1446
            ret.append("&gt;");
 
1447
        else if (ch == '\'')
 
1448
            ret.append("&apos;");
 
1449
        else if (ch == '"')
 
1450
            ret.append("&quot;");
 
1451
        else
 
1452
            ret.push_back(ch);
 
1453
 
 
1454
        }
 
1455
    return ret;
 
1456
}
 
1457
 
 
1458
 
 
1459
int Parser::match(int p0, const char *text)
 
1460
{
 
1461
    int p = p0;
 
1462
    while (*text)
 
1463
        {
 
1464
        if (peek(p) != *text)
 
1465
            return p0;
 
1466
        p++; text++;
 
1467
        }
 
1468
    return p;
 
1469
}
 
1470
 
 
1471
 
 
1472
 
 
1473
int Parser::skipwhite(int p)
 
1474
{
 
1475
 
 
1476
    while (p<parselen)
 
1477
        {
 
1478
        int p2 = match(p, "<!--");
 
1479
        if (p2 > p)
 
1480
            {
 
1481
            p = p2;
 
1482
            while (p<parselen)
 
1483
              {
 
1484
              p2 = match(p, "-->");
 
1485
              if (p2 > p)
 
1486
                  {
 
1487
                  p = p2;
 
1488
                  break;
 
1489
                  }
 
1490
              p++;
 
1491
              }
 
1492
          }
 
1493
      XMLCh b = peek(p);
 
1494
      if (!isspace(b))
 
1495
          break;
 
1496
      p++;
 
1497
      }
 
1498
  return p;
 
1499
}
 
1500
 
 
1501
/* modify this to allow all chars for an element or attribute name*/
 
1502
int Parser::getWord(int p0, String &buf)
 
1503
{
 
1504
    int p = p0;
 
1505
    while (p<parselen)
 
1506
        {
 
1507
        XMLCh b = peek(p);
 
1508
        if (b<=' ' || b=='/' || b=='>' || b=='=')
 
1509
            break;
 
1510
        buf.push_back(b);
 
1511
        p++;
 
1512
        }
 
1513
    return p;
 
1514
}
 
1515
 
 
1516
int Parser::getQuoted(int p0, String &buf, int do_i_parse)
 
1517
{
 
1518
 
 
1519
    int p = p0;
 
1520
    if (peek(p) != '"' && peek(p) != '\'')
 
1521
        return p0;
 
1522
    p++;
 
1523
 
 
1524
    while ( p<parselen )
 
1525
        {
 
1526
        XMLCh b = peek(p);
 
1527
        if (b=='"' || b=='\'')
 
1528
            break;
 
1529
        if (b=='&' && do_i_parse)
 
1530
            {
 
1531
            bool found = false;
 
1532
            for (EntityEntry *ee = entities ; ee->value ; ee++)
 
1533
                {
 
1534
                int p2 = match(p, ee->escaped);
 
1535
                if (p2>p)
 
1536
                    {
 
1537
                    buf.push_back(ee->value);
 
1538
                    p = p2;
 
1539
                    found = true;
 
1540
                    break;
 
1541
                    }
 
1542
                }
 
1543
            if (!found)
 
1544
                {
 
1545
                error("unterminated entity");
 
1546
                return false;
 
1547
                }
 
1548
            }
 
1549
        else
 
1550
            {
 
1551
            buf.push_back(b);
 
1552
            p++;
 
1553
            }
 
1554
        }
 
1555
    return p;
 
1556
}
 
1557
 
 
1558
int Parser::parseVersion(int p0)
 
1559
{
 
1560
    //printf("### parseVersion: %d\n", p0);
 
1561
 
 
1562
    int p = p0;
 
1563
 
 
1564
    p = skipwhite(p0);
 
1565
 
 
1566
    if (peek(p) != '<')
 
1567
        return p0;
 
1568
 
 
1569
    p++;
 
1570
    if (p>=parselen || peek(p)!='?')
 
1571
        return p0;
 
1572
 
 
1573
    p++;
 
1574
 
 
1575
    String buf;
 
1576
 
 
1577
    while (p<parselen)
 
1578
        {
 
1579
        XMLCh ch = peek(p);
 
1580
        if (ch=='?')
 
1581
            {
 
1582
            p++;
 
1583
            break;
 
1584
            }
 
1585
        buf.push_back(ch);
 
1586
        p++;
 
1587
        }
 
1588
 
 
1589
    if (peek(p) != '>')
 
1590
        return p0;
 
1591
    p++;
 
1592
 
 
1593
    //printf("Got version:%s\n",buf.c_str());
 
1594
    return p;
 
1595
}
 
1596
 
 
1597
int Parser::parseDoctype(int p0)
 
1598
{
 
1599
    //printf("### parseDoctype: %d\n", p0);
 
1600
 
 
1601
    int p = p0;
 
1602
    p = skipwhite(p);
 
1603
 
 
1604
    if (p>=parselen || peek(p)!='<')
 
1605
        return p0;
 
1606
 
 
1607
    p++;
 
1608
 
 
1609
    if (peek(p)!='!' || peek(p+1)=='-')
 
1610
        return p0;
 
1611
    p++;
 
1612
 
 
1613
    String buf;
 
1614
    while (p<parselen)
 
1615
        {
 
1616
        XMLCh ch = peek(p);
 
1617
        if (ch=='>')
 
1618
            {
 
1619
            p++;
 
1620
            break;
 
1621
            }
 
1622
        buf.push_back(ch);
 
1623
        p++;
 
1624
        }
 
1625
 
 
1626
    //printf("Got doctype:%s\n",buf.c_str());
 
1627
    return p;
 
1628
}
 
1629
 
 
1630
 
 
1631
 
 
1632
int Parser::parseElement(int p0, Element *par,int lineNr)
 
1633
{
 
1634
 
 
1635
    int p = p0;
 
1636
 
 
1637
    int p2 = p;
 
1638
 
 
1639
    p = skipwhite(p);
 
1640
 
 
1641
    //## Get open tag
 
1642
    XMLCh ch = peek(p);
 
1643
    if (ch!='<')
 
1644
        return p0;
 
1645
 
 
1646
    //int line, col;
 
1647
    //getLineAndColumn(p, &line, &col);
 
1648
 
 
1649
    p++;
 
1650
 
 
1651
    String openTagName;
 
1652
    p = skipwhite(p);
 
1653
    p = getWord(p, openTagName);
 
1654
    //printf("####tag :%s\n", openTagName.c_str());
 
1655
    p = skipwhite(p);
 
1656
 
 
1657
    //Add element to tree
 
1658
    Element *n = new Element(openTagName);
 
1659
    n->line = lineNr + countLines(p0, p);
 
1660
    n->parent = par;
 
1661
    par->addChild(n);
 
1662
 
 
1663
    // Get attributes
 
1664
    if (peek(p) != '>')
 
1665
        {
 
1666
        while (p<parselen)
 
1667
            {
 
1668
            p = skipwhite(p);
 
1669
            ch = peek(p);
 
1670
            //printf("ch:%c\n",ch);
 
1671
            if (ch=='>')
 
1672
                break;
 
1673
            else if (ch=='/' && p<parselen+1)
 
1674
                {
 
1675
                p++;
 
1676
                p = skipwhite(p);
 
1677
                ch = peek(p);
 
1678
                if (ch=='>')
 
1679
                    {
 
1680
                    p++;
 
1681
                    //printf("quick close\n");
 
1682
                    return p;
 
1683
                    }
 
1684
                }
 
1685
            String attrName;
 
1686
            p2 = getWord(p, attrName);
 
1687
            if (p2==p)
 
1688
                break;
 
1689
            //printf("name:%s",buf);
 
1690
            p=p2;
 
1691
            p = skipwhite(p);
 
1692
            ch = peek(p);
 
1693
            //printf("ch:%c\n",ch);
 
1694
            if (ch!='=')
 
1695
                break;
 
1696
            p++;
 
1697
            p = skipwhite(p);
 
1698
            // ch = parsebuf[p];
 
1699
            // printf("ch:%c\n",ch);
 
1700
            String attrVal;
 
1701
            p2 = getQuoted(p, attrVal, true);
 
1702
            p=p2+1;
 
1703
            //printf("name:'%s'   value:'%s'\n",attrName.c_str(),attrVal.c_str());
 
1704
            char *namestr = (char *)attrName.c_str();
 
1705
            if (strncmp(namestr, "xmlns:", 6)==0)
 
1706
                n->addNamespace(attrName, attrVal);
 
1707
            else
 
1708
                n->addAttribute(attrName, attrVal);
 
1709
            }
 
1710
        }
 
1711
 
 
1712
    bool cdata = false;
 
1713
 
 
1714
    p++;
 
1715
    // ### Get intervening data ### */
 
1716
    String data;
 
1717
    while (p<parselen)
 
1718
        {
 
1719
        //# COMMENT
 
1720
        p2 = match(p, "<!--");
 
1721
        if (!cdata && p2>p)
 
1722
            {
 
1723
            p = p2;
 
1724
            while (p<parselen)
 
1725
                {
 
1726
                p2 = match(p, "-->");
 
1727
                if (p2 > p)
 
1728
                    {
 
1729
                    p = p2;
 
1730
                    break;
 
1731
                    }
 
1732
                p++;
 
1733
                }
 
1734
            }
 
1735
 
 
1736
        ch = peek(p);
 
1737
        //# END TAG
 
1738
        if (ch=='<' && !cdata && peek(p+1)=='/')
 
1739
            {
 
1740
            break;
 
1741
            }
 
1742
        //# CDATA
 
1743
        p2 = match(p, "<![CDATA[");
 
1744
        if (p2 > p)
 
1745
            {
 
1746
            cdata = true;
 
1747
            p = p2;
 
1748
            continue;
 
1749
            }
 
1750
 
 
1751
        //# CHILD ELEMENT
 
1752
        if (ch == '<')
 
1753
            {
 
1754
            p2 = parseElement(p, n, lineNr + countLines(p0, p));
 
1755
            if (p2 == p)
 
1756
                {
 
1757
                /*
 
1758
                printf("problem on element:%s.  p2:%d p:%d\n",
 
1759
                      openTagName.c_str(), p2, p);
 
1760
                */
 
1761
                return p0;
 
1762
                }
 
1763
            p = p2;
 
1764
            continue;
 
1765
            }
 
1766
        //# ENTITY
 
1767
        if (ch=='&' && !cdata)
 
1768
            {
 
1769
            bool found = false;
 
1770
            for (EntityEntry *ee = entities ; ee->value ; ee++)
 
1771
                {
 
1772
                int p2 = match(p, ee->escaped);
 
1773
                if (p2>p)
 
1774
                    {
 
1775
                    data.push_back(ee->value);
 
1776
                    p = p2;
 
1777
                    found = true;
 
1778
                    break;
 
1779
                    }
 
1780
                }
 
1781
            if (!found)
 
1782
                {
 
1783
                error("unterminated entity");
 
1784
                return -1;
 
1785
                }
 
1786
            continue;
 
1787
            }
 
1788
 
 
1789
        //# NONE OF THE ABOVE
 
1790
        data.push_back(ch);
 
1791
        p++;
 
1792
        }/*while*/
 
1793
 
 
1794
 
 
1795
    n->value = data;
 
1796
    //printf("%d : data:%s\n",p,data.c_str());
 
1797
 
 
1798
    //## Get close tag
 
1799
    p = skipwhite(p);
 
1800
    ch = peek(p);
 
1801
    if (ch != '<')
 
1802
        {
 
1803
        error("no < for end tag\n");
 
1804
        return p0;
 
1805
        }
 
1806
    p++;
 
1807
    ch = peek(p);
 
1808
    if (ch != '/')
 
1809
        {
 
1810
        error("no / on end tag");
 
1811
        return p0;
 
1812
        }
 
1813
    p++;
 
1814
    ch = peek(p);
 
1815
    p = skipwhite(p);
 
1816
    String closeTagName;
 
1817
    p = getWord(p, closeTagName);
 
1818
    if (openTagName != closeTagName)
 
1819
        {
 
1820
        error("Mismatched closing tag.  Expected </%S>. Got '%S'.",
 
1821
                openTagName.c_str(), closeTagName.c_str());
 
1822
        return p0;
 
1823
        }
 
1824
    p = skipwhite(p);
 
1825
    if (peek(p) != '>')
 
1826
        {
 
1827
        error("no > on end tag for '%s'", closeTagName.c_str());
 
1828
        return p0;
 
1829
        }
 
1830
    p++;
 
1831
    // printf("close element:%s\n",closeTagName.c_str());
 
1832
    p = skipwhite(p);
 
1833
    return p;
 
1834
}
 
1835
 
 
1836
 
 
1837
 
 
1838
 
 
1839
Element *Parser::parse(XMLCh *buf,int pos,int len)
 
1840
{
 
1841
    parselen = len;
 
1842
    parsebuf = buf;
 
1843
    Element *rootNode = new Element("root");
 
1844
    pos = parseVersion(pos);
 
1845
    pos = parseDoctype(pos);
 
1846
    pos = parseElement(pos, rootNode, 1);
 
1847
    return rootNode;
 
1848
}
 
1849
 
 
1850
 
 
1851
Element *Parser::parse(const char *buf, int pos, int len)
 
1852
{
 
1853
    XMLCh *charbuf = new XMLCh[len + 1];
 
1854
    long i = 0;
 
1855
    for ( ; i < len ; i++)
 
1856
        charbuf[i] = (XMLCh)buf[i];
 
1857
    charbuf[i] = '\0';
 
1858
 
 
1859
    Element *n = parse(charbuf, pos, len);
 
1860
    delete[] charbuf;
 
1861
    return n;
 
1862
}
 
1863
 
 
1864
Element *Parser::parse(const String &buf)
 
1865
{
 
1866
    long len = (long)buf.size();
 
1867
    XMLCh *charbuf = new XMLCh[len + 1];
 
1868
    long i = 0;
 
1869
    for ( ; i < len ; i++)
 
1870
        charbuf[i] = (XMLCh)buf[i];
 
1871
    charbuf[i] = '\0';
 
1872
 
 
1873
    Element *n = parse(charbuf, 0, len);
 
1874
    delete[] charbuf;
 
1875
    return n;
 
1876
}
 
1877
 
 
1878
Element *Parser::parseFile(const String &fileName)
 
1879
{
 
1880
 
 
1881
    //##### LOAD INTO A CHAR BUF, THEN CONVERT TO XMLCh
 
1882
    FILE *f = fopen(fileName.c_str(), "rb");
 
1883
    if (!f)
 
1884
        return NULL;
 
1885
 
 
1886
    struct stat  statBuf;
 
1887
    if (fstat(fileno(f),&statBuf)<0)
 
1888
        {
 
1889
        fclose(f);
 
1890
        return NULL;
 
1891
        }
 
1892
    long filelen = statBuf.st_size;
 
1893
 
 
1894
    //printf("length:%d\n",filelen);
 
1895
    XMLCh *charbuf = new XMLCh[filelen + 1];
 
1896
    for (XMLCh *p=charbuf ; !feof(f) ; p++)
 
1897
        {
 
1898
        *p = (XMLCh)fgetc(f);
 
1899
        }
 
1900
    fclose(f);
 
1901
    charbuf[filelen] = '\0';
 
1902
 
 
1903
 
 
1904
    /*
 
1905
    printf("nrbytes:%d\n",wc_count);
 
1906
    printf("buf:%ls\n======\n",charbuf);
 
1907
    */
 
1908
    Element *n = parse(charbuf, 0, filelen);
 
1909
    delete[] charbuf;
 
1910
    return n;
 
1911
}
 
1912
 
 
1913
//########################################################################
 
1914
//########################################################################
 
1915
//##  E N D    X M L
 
1916
//########################################################################
 
1917
//########################################################################
 
1918
 
 
1919
 
 
1920
 
 
1921
 
 
1922
 
 
1923
 
 
1924
//########################################################################
 
1925
//########################################################################
 
1926
//##  U R I
 
1927
//########################################################################
 
1928
//########################################################################
 
1929
 
 
1930
//This would normally be a call to a UNICODE function
 
1931
#define isLetter(x) isalpha(x)
 
1932
 
 
1933
/**
 
1934
 *  A class that implements the W3C URI resource reference.
 
1935
 */
 
1936
class URI
 
1937
{
 
1938
public:
 
1939
 
 
1940
    typedef enum
 
1941
        {
 
1942
        SCHEME_NONE =0,
 
1943
        SCHEME_DATA,
 
1944
        SCHEME_HTTP,
 
1945
        SCHEME_HTTPS,
 
1946
        SCHEME_FTP,
 
1947
        SCHEME_FILE,
 
1948
        SCHEME_LDAP,
 
1949
        SCHEME_MAILTO,
 
1950
        SCHEME_NEWS,
 
1951
        SCHEME_TELNET
 
1952
        } SchemeTypes;
 
1953
 
 
1954
    /**
 
1955
     *
 
1956
     */
 
1957
    URI()
 
1958
        {
 
1959
        init();
 
1960
        }
 
1961
 
 
1962
    /**
 
1963
     *
 
1964
     */
 
1965
    URI(const String &str)
 
1966
        {
 
1967
        init();
 
1968
        parse(str);
 
1969
        }
 
1970
 
 
1971
 
 
1972
    /**
 
1973
     *
 
1974
     */
 
1975
    URI(const char *str)
 
1976
        {
 
1977
        init();
 
1978
        String domStr = str;
 
1979
        parse(domStr);
 
1980
        }
 
1981
 
 
1982
 
 
1983
    /**
 
1984
     *
 
1985
     */
 
1986
    URI(const URI &other)
 
1987
        {
 
1988
        init();
 
1989
        assign(other);
 
1990
        }
 
1991
 
 
1992
 
 
1993
    /**
 
1994
     *
 
1995
     */
 
1996
    URI &operator=(const URI &other)
 
1997
        {
 
1998
        init();
 
1999
        assign(other);
 
2000
        return *this;
 
2001
        }
 
2002
 
 
2003
 
 
2004
    /**
 
2005
     *
 
2006
     */
 
2007
    virtual ~URI()
 
2008
        {}
 
2009
 
 
2010
 
 
2011
 
 
2012
    /**
 
2013
     *
 
2014
     */
 
2015
    virtual bool parse(const String &str);
 
2016
 
 
2017
    /**
 
2018
     *
 
2019
     */
 
2020
    virtual String toString() const;
 
2021
 
 
2022
    /**
 
2023
     *
 
2024
     */
 
2025
    virtual int getScheme() const;
 
2026
 
 
2027
    /**
 
2028
     *
 
2029
     */
 
2030
    virtual String getSchemeStr() const;
 
2031
 
 
2032
    /**
 
2033
     *
 
2034
     */
 
2035
    virtual String getAuthority() const;
 
2036
 
 
2037
    /**
 
2038
     *  Same as getAuthority, but if the port has been specified
 
2039
     *  as host:port , the port will not be included
 
2040
     */
 
2041
    virtual String getHost() const;
 
2042
 
 
2043
    /**
 
2044
     *
 
2045
     */
 
2046
    virtual int getPort() const;
 
2047
 
 
2048
    /**
 
2049
     *
 
2050
     */
 
2051
    virtual String getPath() const;
 
2052
 
 
2053
    /**
 
2054
     *
 
2055
     */
 
2056
    virtual String getNativePath() const;
 
2057
 
 
2058
    /**
 
2059
     *
 
2060
     */
 
2061
    virtual bool isAbsolute() const;
 
2062
 
 
2063
    /**
 
2064
     *
 
2065
     */
 
2066
    virtual bool isOpaque() const;
 
2067
 
 
2068
    /**
 
2069
     *
 
2070
     */
 
2071
    virtual String getQuery() const;
 
2072
 
 
2073
    /**
 
2074
     *
 
2075
     */
 
2076
    virtual String getFragment() const;
 
2077
 
 
2078
    /**
 
2079
     *
 
2080
     */
 
2081
    virtual URI resolve(const URI &other) const;
 
2082
 
 
2083
    /**
 
2084
     *
 
2085
     */
 
2086
    virtual void normalize();
 
2087
 
 
2088
private:
 
2089
 
 
2090
    /**
 
2091
     *
 
2092
     */
 
2093
    void init()
 
2094
        {
 
2095
        parsebuf  = NULL;
 
2096
        parselen  = 0;
 
2097
        scheme    = SCHEME_NONE;
 
2098
        schemeStr = "";
 
2099
        port      = 0;
 
2100
        authority = "";
 
2101
        path      = "";
 
2102
        absolute  = false;
 
2103
        opaque    = false;
 
2104
        query     = "";
 
2105
        fragment  = "";
 
2106
        }
 
2107
 
 
2108
 
 
2109
    /**
 
2110
     *
 
2111
     */
 
2112
    void assign(const URI &other)
 
2113
        {
 
2114
        scheme    = other.scheme;
 
2115
        schemeStr = other.schemeStr;
 
2116
        authority = other.authority;
 
2117
        port      = other.port;
 
2118
        path      = other.path;
 
2119
        absolute  = other.absolute;
 
2120
        opaque    = other.opaque;
 
2121
        query     = other.query;
 
2122
        fragment  = other.fragment;
 
2123
        }
 
2124
 
 
2125
    int scheme;
 
2126
 
 
2127
    String schemeStr;
 
2128
 
 
2129
    String authority;
 
2130
 
 
2131
    bool portSpecified;
 
2132
 
 
2133
    int port;
 
2134
 
 
2135
    String path;
 
2136
 
 
2137
    bool absolute;
 
2138
 
 
2139
    bool opaque;
 
2140
 
 
2141
    String query;
 
2142
 
 
2143
    String fragment;
 
2144
 
 
2145
    void error(const char *fmt, ...);
 
2146
 
 
2147
    void trace(const char *fmt, ...);
 
2148
 
 
2149
 
 
2150
    int peek(int p);
 
2151
 
 
2152
    int match(int p, const char *key);
 
2153
 
 
2154
    int parseScheme(int p);
 
2155
 
 
2156
    int parseHierarchicalPart(int p0);
 
2157
 
 
2158
    int parseQuery(int p0);
 
2159
 
 
2160
    int parseFragment(int p0);
 
2161
 
 
2162
    int parse(int p);
 
2163
 
 
2164
    char *parsebuf;
 
2165
 
 
2166
    int parselen;
 
2167
 
 
2168
};
 
2169
 
 
2170
 
 
2171
 
 
2172
typedef struct
 
2173
{
 
2174
    int         ival;
 
2175
    const char *sval;
 
2176
    int         port;
 
2177
} LookupEntry;
 
2178
 
 
2179
LookupEntry schemes[] =
 
2180
{
 
2181
    { URI::SCHEME_DATA,   "data:",    0 },
 
2182
    { URI::SCHEME_HTTP,   "http:",   80 },
 
2183
    { URI::SCHEME_HTTPS,  "https:", 443 },
 
2184
    { URI::SCHEME_FTP,    "ftp",     12 },
 
2185
    { URI::SCHEME_FILE,   "file:",    0 },
 
2186
    { URI::SCHEME_LDAP,   "ldap:",  123 },
 
2187
    { URI::SCHEME_MAILTO, "mailto:", 25 },
 
2188
    { URI::SCHEME_NEWS,   "news:",  117 },
 
2189
    { URI::SCHEME_TELNET, "telnet:", 23 },
 
2190
    { 0,                  NULL,       0 }
 
2191
};
 
2192
 
 
2193
 
 
2194
String URI::toString() const
 
2195
{
 
2196
    String str = schemeStr;
 
2197
    if (authority.size() > 0)
 
2198
        {
 
2199
        str.append("//");
 
2200
        str.append(authority);
 
2201
        }
 
2202
    str.append(path);
 
2203
    if (query.size() > 0)
 
2204
        {
 
2205
        str.append("?");
 
2206
        str.append(query);
 
2207
        }
 
2208
    if (fragment.size() > 0)
 
2209
        {
 
2210
        str.append("#");
 
2211
        str.append(fragment);
 
2212
        }
 
2213
    return str;
 
2214
}
 
2215
 
 
2216
 
 
2217
int URI::getScheme() const
 
2218
{
 
2219
    return scheme;
 
2220
}
 
2221
 
 
2222
String URI::getSchemeStr() const
 
2223
{
 
2224
    return schemeStr;
 
2225
}
 
2226
 
 
2227
 
 
2228
String URI::getAuthority() const
 
2229
{
 
2230
    String ret = authority;
 
2231
    if (portSpecified && port>=0)
 
2232
        {
 
2233
        char buf[7];
 
2234
        snprintf(buf, 6, ":%6d", port);
 
2235
        ret.append(buf);
 
2236
        }
 
2237
    return ret;
 
2238
}
 
2239
 
 
2240
String URI::getHost() const
 
2241
{
 
2242
    return authority;
 
2243
}
 
2244
 
 
2245
int URI::getPort() const
 
2246
{
 
2247
    return port;
 
2248
}
 
2249
 
 
2250
 
 
2251
String URI::getPath() const
 
2252
{
 
2253
    return path;
 
2254
}
 
2255
 
 
2256
String URI::getNativePath() const
 
2257
{
 
2258
    String npath;
 
2259
#ifdef __WIN32__
 
2260
    unsigned int firstChar = 0;
 
2261
    if (path.size() >= 3)
 
2262
        {
 
2263
        if (path[0] == '/' &&
 
2264
            isLetter(path[1]) &&
 
2265
            path[2] == ':')
 
2266
            firstChar++;
 
2267
         }
 
2268
    for (unsigned int i=firstChar ; i<path.size() ; i++)
 
2269
        {
 
2270
        XMLCh ch = (XMLCh) path[i];
 
2271
        if (ch == '/')
 
2272
            npath.push_back((XMLCh)'\\');
 
2273
        else
 
2274
            npath.push_back(ch);
 
2275
        }
 
2276
#else
 
2277
    npath = path;
 
2278
#endif
 
2279
    return npath;
 
2280
}
 
2281
 
 
2282
 
 
2283
bool URI::isAbsolute() const
 
2284
{
 
2285
    return absolute;
 
2286
}
 
2287
 
 
2288
bool URI::isOpaque() const
 
2289
{
 
2290
    return opaque;
 
2291
}
 
2292
 
 
2293
 
 
2294
String URI::getQuery() const
 
2295
{
 
2296
    return query;
 
2297
}
 
2298
 
 
2299
 
 
2300
String URI::getFragment() const
 
2301
{
 
2302
    return fragment;
 
2303
}
 
2304
 
 
2305
 
 
2306
URI URI::resolve(const URI &other) const
 
2307
{
 
2308
    //### According to w3c, this is handled in 3 cases
 
2309
 
 
2310
    //## 1
 
2311
    if (opaque || other.isAbsolute())
 
2312
        return other;
 
2313
 
 
2314
    //## 2
 
2315
    if (other.fragment.size()  >  0 &&
 
2316
        other.path.size()      == 0 &&
 
2317
        other.scheme           == SCHEME_NONE &&
 
2318
        other.authority.size() == 0 &&
 
2319
        other.query.size()     == 0 )
 
2320
        {
 
2321
        URI fragUri = *this;
 
2322
        fragUri.fragment = other.fragment;
 
2323
        return fragUri;
 
2324
        }
 
2325
 
 
2326
    //## 3 http://www.ietf.org/rfc/rfc2396.txt, section 5.2
 
2327
    URI newUri;
 
2328
    //# 3.1
 
2329
    newUri.scheme    = scheme;
 
2330
    newUri.schemeStr = schemeStr;
 
2331
    newUri.query     = other.query;
 
2332
    newUri.fragment  = other.fragment;
 
2333
    if (other.authority.size() > 0)
 
2334
        {
 
2335
        //# 3.2
 
2336
        if (absolute || other.absolute)
 
2337
            newUri.absolute = true;
 
2338
        newUri.authority = other.authority;
 
2339
        newUri.port      = other.port;//part of authority
 
2340
        newUri.path      = other.path;
 
2341
        }
 
2342
    else
 
2343
        {
 
2344
        //# 3.3
 
2345
        if (other.absolute)
 
2346
            {
 
2347
            newUri.absolute = true;
 
2348
            newUri.path     = other.path;
 
2349
            }
 
2350
        else
 
2351
            {
 
2352
            unsigned int pos = path.find_last_of('/');
 
2353
            if (pos != path.npos)
 
2354
                {
 
2355
                String tpath = path.substr(0, pos+1);
 
2356
                tpath.append(other.path);
 
2357
                newUri.path = tpath;
 
2358
                }
 
2359
            else
 
2360
                newUri.path = other.path;
 
2361
            }
 
2362
        }
 
2363
 
 
2364
    newUri.normalize();
 
2365
    return newUri;
 
2366
}
 
2367
 
 
2368
 
 
2369
 
 
2370
/**
 
2371
 *  This follows the Java URI algorithm:
 
2372
 *   1. All "." segments are removed.
 
2373
 *   2. If a ".." segment is preceded by a non-".." segment
 
2374
 *          then both of these segments are removed. This step
 
2375
 *          is repeated until it is no longer applicable.
 
2376
 *   3. If the path is relative, and if its first segment
 
2377
 *          contains a colon character (':'), then a "." segment
 
2378
 *          is prepended. This prevents a relative URI with a path
 
2379
 *          such as "a:b/c/d" from later being re-parsed as an
 
2380
 *          opaque URI with a scheme of "a" and a scheme-specific
 
2381
 *          part of "b/c/d". (Deviation from RFC 2396)
 
2382
 */
 
2383
void URI::normalize()
 
2384
{
 
2385
    std::vector<String> segments;
 
2386
 
 
2387
    //## Collect segments
 
2388
    if (path.size()<2)
 
2389
        return;
 
2390
    bool abs = false;
 
2391
    unsigned int pos=0;
 
2392
    if (path[0]=='/')
 
2393
        {
 
2394
        abs = true;
 
2395
        pos++;
 
2396
        }
 
2397
    while (pos < path.size())
 
2398
        {
 
2399
        unsigned int pos2 = path.find('/', pos);
 
2400
        if (pos2==path.npos)
 
2401
            {
 
2402
            String seg = path.substr(pos);
 
2403
            //printf("last segment:%s\n", seg.c_str());
 
2404
            segments.push_back(seg);
 
2405
            break;
 
2406
            }
 
2407
        if (pos2>pos)
 
2408
            {
 
2409
            String seg = path.substr(pos, pos2-pos);
 
2410
            //printf("segment:%s\n", seg.c_str());
 
2411
            segments.push_back(seg);
 
2412
            }
 
2413
        pos = pos2;
 
2414
        pos++;
 
2415
        }
 
2416
 
 
2417
    //## Clean up (normalize) segments
 
2418
    bool edited = false;
 
2419
    std::vector<String>::iterator iter;
 
2420
    for (iter=segments.begin() ; iter!=segments.end() ; )
 
2421
        {
 
2422
        String s = *iter;
 
2423
        if (s == ".")
 
2424
            {
 
2425
            iter = segments.erase(iter);
 
2426
            edited = true;
 
2427
            }
 
2428
        else if (s == ".." &&
 
2429
                 iter != segments.begin() &&
 
2430
                 *(iter-1) != "..")
 
2431
            {
 
2432
            iter--; //back up, then erase two entries
 
2433
            iter = segments.erase(iter);
 
2434
            iter = segments.erase(iter);
 
2435
            edited = true;
 
2436
            }
 
2437
        else
 
2438
            iter++;
 
2439
        }
 
2440
 
 
2441
    //## Rebuild path, if necessary
 
2442
    if (edited)
 
2443
        {
 
2444
        path.clear();
 
2445
        if (abs)
 
2446
            {
 
2447
            path.append("/");
 
2448
            }
 
2449
        std::vector<String>::iterator iter;
 
2450
        for (iter=segments.begin() ; iter!=segments.end() ; iter++)
 
2451
            {
 
2452
            if (iter != segments.begin())
 
2453
                path.append("/");
 
2454
            path.append(*iter);
 
2455
            }
 
2456
        }
 
2457
 
 
2458
}
 
2459
 
 
2460
 
 
2461
 
 
2462
//#########################################################################
 
2463
//# M E S S A G E S
 
2464
//#########################################################################
 
2465
 
 
2466
void URI::error(const char *fmt, ...)
 
2467
{
 
2468
    va_list args;
 
2469
    fprintf(stderr, "URI error: ");
 
2470
    va_start(args, fmt);
 
2471
    vfprintf(stderr, fmt, args);
 
2472
    va_end(args);
 
2473
    fprintf(stderr, "\n");
 
2474
}
 
2475
 
 
2476
void URI::trace(const char *fmt, ...)
 
2477
{
 
2478
    va_list args;
 
2479
    fprintf(stdout, "URI: ");
 
2480
    va_start(args, fmt);
 
2481
    vfprintf(stdout, fmt, args);
 
2482
    va_end(args);
 
2483
    fprintf(stdout, "\n");
 
2484
}
 
2485
 
 
2486
 
 
2487
 
 
2488
 
 
2489
//#########################################################################
 
2490
//# P A R S I N G
 
2491
//#########################################################################
 
2492
 
 
2493
 
 
2494
 
 
2495
int URI::peek(int p)
 
2496
{
 
2497
    if (p<0 || p>=parselen)
 
2498
        return -1;
 
2499
    return parsebuf[p];
 
2500
}
 
2501
 
 
2502
 
 
2503
 
 
2504
int URI::match(int p0, const char *key)
 
2505
{
 
2506
    int p = p0;
 
2507
    while (p < parselen)
 
2508
        {
 
2509
        if (*key == '\0')
 
2510
            return p;
 
2511
        else if (*key != parsebuf[p])
 
2512
            break;
 
2513
        p++; key++;
 
2514
        }
 
2515
    return p0;
 
2516
}
 
2517
 
 
2518
//#########################################################################
 
2519
//#  Parsing is performed according to:
 
2520
//#  http://www.gbiv.com/protocols/uri/rfc/rfc3986.html#components
 
2521
//#########################################################################
 
2522
 
 
2523
int URI::parseScheme(int p0)
 
2524
{
 
2525
    int p = p0;
 
2526
    for (LookupEntry *entry = schemes; entry->sval ; entry++)
 
2527
        {
 
2528
        int p2 = match(p, entry->sval);
 
2529
        if (p2 > p)
 
2530
            {
 
2531
            schemeStr = entry->sval;
 
2532
            scheme    = entry->ival;
 
2533
            port      = entry->port;
 
2534
            p = p2;
 
2535
            return p;
 
2536
            }
 
2537
        }
 
2538
 
 
2539
    return p;
 
2540
}
 
2541
 
 
2542
 
 
2543
int URI::parseHierarchicalPart(int p0)
 
2544
{
 
2545
    int p = p0;
 
2546
    int ch;
 
2547
 
 
2548
    //# Authority field (host and port, for example)
 
2549
    int p2 = match(p, "//");
 
2550
    if (p2 > p)
 
2551
        {
 
2552
        p = p2;
 
2553
        portSpecified = false;
 
2554
        String portStr;
 
2555
        while (p < parselen)
 
2556
            {
 
2557
            ch = peek(p);
 
2558
            if (ch == '/')
 
2559
                break;
 
2560
            else if (ch == ':')
 
2561
                portSpecified = true;
 
2562
            else if (portSpecified)
 
2563
                portStr.push_back((XMLCh)ch);
 
2564
            else
 
2565
                authority.push_back((XMLCh)ch);
 
2566
            p++;
 
2567
            }
 
2568
        if (portStr.size() > 0)
 
2569
            {
 
2570
            char *pstr = (char *)portStr.c_str();
 
2571
            char *endStr;
 
2572
            long val = strtol(pstr, &endStr, 10);
 
2573
            if (endStr > pstr) //successful parse?
 
2574
                port = val;
 
2575
            }
 
2576
        }
 
2577
 
 
2578
    //# Are we absolute?
 
2579
    ch = peek(p);
 
2580
    if (isLetter(ch) && peek(p+1)==':')
 
2581
        {
 
2582
        absolute = true;
 
2583
        path.push_back((XMLCh)'/');
 
2584
        }
 
2585
    else if (ch == '/')
 
2586
        {
 
2587
        absolute = true;
 
2588
        if (p>p0) //in other words, if '/' is not the first char
 
2589
            opaque = true;
 
2590
        path.push_back((XMLCh)ch);
 
2591
        p++;
 
2592
        }
 
2593
 
 
2594
    while (p < parselen)
 
2595
        {
 
2596
        ch = peek(p);
 
2597
        if (ch == '?' || ch == '#')
 
2598
            break;
 
2599
        path.push_back((XMLCh)ch);
 
2600
        p++;
 
2601
        }
 
2602
 
 
2603
    return p;
 
2604
}
 
2605
 
 
2606
int URI::parseQuery(int p0)
 
2607
{
 
2608
    int p = p0;
 
2609
    int ch = peek(p);
 
2610
    if (ch != '?')
 
2611
        return p0;
 
2612
 
 
2613
    p++;
 
2614
    while (p < parselen)
 
2615
        {
 
2616
        ch = peek(p);
 
2617
        if (ch == '#')
 
2618
            break;
 
2619
        query.push_back((XMLCh)ch);
 
2620
        p++;
 
2621
        }
 
2622
 
 
2623
 
 
2624
    return p;
 
2625
}
 
2626
 
 
2627
int URI::parseFragment(int p0)
 
2628
{
 
2629
 
 
2630
    int p = p0;
 
2631
    int ch = peek(p);
 
2632
    if (ch != '#')
 
2633
        return p0;
 
2634
 
 
2635
    p++;
 
2636
    while (p < parselen)
 
2637
        {
 
2638
        ch = peek(p);
 
2639
        if (ch == '?')
 
2640
            break;
 
2641
        fragment.push_back((XMLCh)ch);
 
2642
        p++;
 
2643
        }
 
2644
 
 
2645
 
 
2646
    return p;
 
2647
}
 
2648
 
 
2649
 
 
2650
int URI::parse(int p0)
 
2651
{
 
2652
 
 
2653
    int p = p0;
 
2654
 
 
2655
    int p2 = parseScheme(p);
 
2656
    if (p2 < 0)
 
2657
        {
 
2658
        error("Scheme");
 
2659
        return -1;
 
2660
        }
 
2661
    p = p2;
 
2662
 
 
2663
 
 
2664
    p2 = parseHierarchicalPart(p);
 
2665
    if (p2 < 0)
 
2666
        {
 
2667
        error("Hierarchical part");
 
2668
        return -1;
 
2669
        }
 
2670
    p = p2;
 
2671
 
 
2672
    p2 = parseQuery(p);
 
2673
    if (p2 < 0)
 
2674
        {
 
2675
        error("Query");
 
2676
        return -1;
 
2677
        }
 
2678
    p = p2;
 
2679
 
 
2680
 
 
2681
    p2 = parseFragment(p);
 
2682
    if (p2 < 0)
 
2683
        {
 
2684
        error("Fragment");
 
2685
        return -1;
 
2686
        }
 
2687
    p = p2;
 
2688
 
 
2689
    return p;
 
2690
 
 
2691
}
 
2692
 
 
2693
 
 
2694
 
 
2695
bool URI::parse(const String &str)
 
2696
{
 
2697
    init();
 
2698
    
 
2699
    parselen = str.size();
 
2700
 
 
2701
    String tmp;
 
2702
    for (unsigned int i=0 ; i<str.size() ; i++)
 
2703
        {
 
2704
        XMLCh ch = (XMLCh) str[i];
 
2705
        if (ch == '\\')
 
2706
            tmp.push_back((XMLCh)'/');
 
2707
        else
 
2708
            tmp.push_back(ch);
 
2709
        }
 
2710
    parsebuf = (char *) tmp.c_str();
 
2711
 
 
2712
 
 
2713
    int p = parse(0);
 
2714
    normalize();
 
2715
 
 
2716
    if (p < 0)
 
2717
        {
 
2718
        error("Syntax error");
 
2719
        return false;
 
2720
        }
 
2721
 
 
2722
    //printf("uri:%s\n", toString().c_str());
 
2723
    //printf("path:%s\n", path.c_str());
 
2724
 
 
2725
    return true;
 
2726
 
 
2727
}
 
2728
 
 
2729
 
 
2730
 
 
2731
 
 
2732
 
 
2733
 
 
2734
 
 
2735
 
 
2736
//########################################################################
 
2737
//########################################################################
 
2738
//##  M A K E
 
2739
//########################################################################
 
2740
//########################################################################
 
2741
 
 
2742
//########################################################################
 
2743
//# F I L E S E T
 
2744
//########################################################################
 
2745
/**
 
2746
 * This is the descriptor for a <fileset> item
 
2747
 */
 
2748
class FileSet
 
2749
{
 
2750
public:
 
2751
 
 
2752
    /**
 
2753
     *
 
2754
     */
 
2755
    FileSet()
 
2756
        {}
 
2757
 
 
2758
    /**
 
2759
     *
 
2760
     */
 
2761
    FileSet(const FileSet &other)
 
2762
        { assign(other); }
 
2763
 
 
2764
    /**
 
2765
     *
 
2766
     */
 
2767
    FileSet &operator=(const FileSet &other)
 
2768
        { assign(other); return *this; }
 
2769
 
 
2770
    /**
 
2771
     *
 
2772
     */
 
2773
    virtual ~FileSet()
 
2774
        {}
 
2775
 
 
2776
    /**
 
2777
     *
 
2778
     */
 
2779
    String getDirectory()
 
2780
        { return directory; }
 
2781
        
 
2782
    /**
 
2783
     *
 
2784
     */
 
2785
    void setDirectory(const String &val)
 
2786
        { directory = val; }
 
2787
 
 
2788
    /**
 
2789
     *
 
2790
     */
 
2791
    void setFiles(const std::vector<String> &val)
 
2792
        { files = val; }
 
2793
 
 
2794
    /**
 
2795
     *
 
2796
     */
 
2797
    std::vector<String> getFiles()
 
2798
        { return files; }
 
2799
        
 
2800
    /**
 
2801
     *
 
2802
     */
 
2803
    void setIncludes(const std::vector<String> &val)
 
2804
        { includes = val; }
 
2805
 
 
2806
    /**
 
2807
     *
 
2808
     */
 
2809
    std::vector<String> getIncludes()
 
2810
        { return includes; }
 
2811
        
 
2812
    /**
 
2813
     *
 
2814
     */
 
2815
    void setExcludes(const std::vector<String> &val)
 
2816
        { excludes = val; }
 
2817
 
 
2818
    /**
 
2819
     *
 
2820
     */
 
2821
    std::vector<String> getExcludes()
 
2822
        { return excludes; }
 
2823
        
 
2824
    /**
 
2825
     *
 
2826
     */
 
2827
    unsigned int size()
 
2828
        { return files.size(); }
 
2829
        
 
2830
    /**
 
2831
     *
 
2832
     */
 
2833
    String operator[](int index)
 
2834
        { return files[index]; }
 
2835
        
 
2836
    /**
 
2837
     *
 
2838
     */
 
2839
    void clear()
 
2840
        {
 
2841
        directory = "";
 
2842
        files.clear();
 
2843
        includes.clear();
 
2844
        excludes.clear();
 
2845
        }
 
2846
        
 
2847
 
 
2848
private:
 
2849
 
 
2850
    void assign(const FileSet &other)
 
2851
        {
 
2852
        directory = other.directory;
 
2853
        files     = other.files;
 
2854
        includes  = other.includes;
 
2855
        excludes  = other.excludes;
 
2856
        }
 
2857
 
 
2858
    String directory;
 
2859
    std::vector<String> files;
 
2860
    std::vector<String> includes;
 
2861
    std::vector<String> excludes;
 
2862
};
 
2863
 
 
2864
 
 
2865
 
 
2866
 
 
2867
//########################################################################
 
2868
//# M A K E    B A S E
 
2869
//########################################################################
 
2870
/**
 
2871
 * Base class for all classes in this file
 
2872
 */
 
2873
class MakeBase
 
2874
{
 
2875
public:
 
2876
 
 
2877
    MakeBase()
 
2878
        { line = 0; }
 
2879
    virtual ~MakeBase()
 
2880
        {}
 
2881
 
 
2882
    /**
 
2883
     *     Return the URI of the file associated with this object 
 
2884
     */     
 
2885
    URI getURI()
 
2886
        { return uri; }
 
2887
 
 
2888
    /**
 
2889
     * Set the uri to the given string
 
2890
     */
 
2891
    void setURI(const String &uristr)
 
2892
        { uri.parse(uristr); }
 
2893
 
 
2894
    /**
 
2895
     *  Resolve another path relative to this one
 
2896
     */
 
2897
    String resolve(const String &otherPath);
 
2898
 
 
2899
    /**
 
2900
     *  Get an element attribute, performing substitutions if necessary
 
2901
     */
 
2902
    bool getAttribute(Element *elem, const String &name, String &result);
 
2903
 
 
2904
    /**
 
2905
     * Get an element value, performing substitutions if necessary
 
2906
     */
 
2907
    bool getValue(Element *elem, String &result);
 
2908
    
 
2909
    /**
 
2910
     * Set the current line number in the file
 
2911
     */         
 
2912
    void setLine(int val)
 
2913
        { line = val; }
 
2914
        
 
2915
    /**
 
2916
     * Get the current line number in the file
 
2917
     */         
 
2918
    int getLine()
 
2919
        { return line; }
 
2920
 
 
2921
 
 
2922
    /**
 
2923
     * Set a property to a given value
 
2924
     */
 
2925
    virtual void setProperty(const String &name, const String &val)
 
2926
        {
 
2927
        properties[name] = val;
 
2928
        }
 
2929
 
 
2930
    /**
 
2931
     * Return a named property is found, else a null string
 
2932
     */
 
2933
    virtual String getProperty(const String &name)
 
2934
        {
 
2935
        String val;
 
2936
        std::map<String, String>::iterator iter = properties.find(name);
 
2937
        if (iter != properties.end())
 
2938
            val = iter->second;
 
2939
        return val;
 
2940
        }
 
2941
 
 
2942
    /**
 
2943
     * Return true if a named property is found, else false
 
2944
     */
 
2945
    virtual bool hasProperty(const String &name)
 
2946
        {
 
2947
        std::map<String, String>::iterator iter = properties.find(name);
 
2948
        if (iter == properties.end())
 
2949
            return false;
 
2950
        return true;
 
2951
        }
 
2952
 
 
2953
 
 
2954
protected:
 
2955
 
 
2956
    /**
 
2957
     *    The path to the file associated with this object
 
2958
     */     
 
2959
    URI uri;
 
2960
    
 
2961
    /**
 
2962
     *    If this prefix is seen in a substitution, use an environment
 
2963
     *    variable.
 
2964
     *             example:  <property environment="env"/>
 
2965
     *             ${env.JAVA_HOME}              
 
2966
     */     
 
2967
    String envPrefix;
 
2968
 
 
2969
 
 
2970
 
 
2971
 
 
2972
    /**
 
2973
     *  Print a printf()-like formatted error message
 
2974
     */
 
2975
    void error(const char *fmt, ...);
 
2976
 
 
2977
    /**
 
2978
     *  Print a printf()-like formatted trace message
 
2979
     */
 
2980
    void status(const char *fmt, ...);
 
2981
 
 
2982
    /**
 
2983
     *  Print a printf()-like formatted trace message
 
2984
     */
 
2985
    void trace(const char *fmt, ...);
 
2986
 
 
2987
    /**
 
2988
     *  Check if a given string matches a given regex pattern
 
2989
     */
 
2990
    bool regexMatch(const String &str, const String &pattern);
 
2991
 
 
2992
    /**
 
2993
     *
 
2994
     */
 
2995
    String getSuffix(const String &fname);
 
2996
 
 
2997
    /**
 
2998
     * Break up a string into substrings delimited the characters
 
2999
     * in delimiters.  Null-length substrings are ignored
 
3000
     */  
 
3001
    std::vector<String> tokenize(const String &val,
 
3002
                          const String &delimiters);
 
3003
 
 
3004
    /**
 
3005
     *  replace runs of whitespace with a space
 
3006
     */
 
3007
    String strip(const String &s);
 
3008
 
 
3009
    /**
 
3010
     *  remove leading whitespace from each line
 
3011
     */
 
3012
    String leftJustify(const String &s);
 
3013
 
 
3014
    /**
 
3015
     *  remove leading and trailing whitespace from string
 
3016
     */
 
3017
    String trim(const String &s);
 
3018
 
 
3019
    /**
 
3020
     *  Return a lower case version of the given string
 
3021
     */
 
3022
    String toLower(const String &s);
 
3023
 
 
3024
    /**
 
3025
     * Return the native format of the canonical
 
3026
     * path which we store
 
3027
     */
 
3028
    String getNativePath(const String &path);
 
3029
 
 
3030
    /**
 
3031
     * Execute a shell command.  Outbuf is a ref to a string
 
3032
     * to catch the result.     
 
3033
     */         
 
3034
    bool executeCommand(const String &call,
 
3035
                        const String &inbuf,
 
3036
                        String &outbuf,
 
3037
                        String &errbuf);
 
3038
    /**
 
3039
     * List all directories in a given base and starting directory
 
3040
     * It is usually called like:
 
3041
     *        bool ret = listDirectories("src", "", result);    
 
3042
     */         
 
3043
    bool listDirectories(const String &baseName,
 
3044
                         const String &dirname,
 
3045
                         std::vector<String> &res);
 
3046
 
 
3047
    /**
 
3048
     * Find all files in the named directory 
 
3049
     */         
 
3050
    bool listFiles(const String &baseName,
 
3051
                   const String &dirname,
 
3052
                   std::vector<String> &result);
 
3053
 
 
3054
    /**
 
3055
     * Perform a listing for a fileset 
 
3056
     */         
 
3057
    bool listFiles(MakeBase &propRef, FileSet &fileSet);
 
3058
 
 
3059
    /**
 
3060
     * Parse a <patternset>
 
3061
     */  
 
3062
    bool parsePatternSet(Element *elem,
 
3063
                       MakeBase &propRef,
 
3064
                       std::vector<String> &includes,
 
3065
                       std::vector<String> &excludes);
 
3066
 
 
3067
    /**
 
3068
     * Parse a <fileset> entry, and determine which files
 
3069
     * should be included
 
3070
     */  
 
3071
    bool parseFileSet(Element *elem,
 
3072
                    MakeBase &propRef,
 
3073
                    FileSet &fileSet);
 
3074
 
 
3075
    /**
 
3076
     * Return this object's property list
 
3077
     */
 
3078
    virtual std::map<String, String> &getProperties()
 
3079
        { return properties; }
 
3080
 
 
3081
 
 
3082
    std::map<String, String> properties;
 
3083
 
 
3084
    /**
 
3085
     * Turn 'true' and 'false' into boolean values
 
3086
     */             
 
3087
    bool getBool(const String &str, bool &val);
 
3088
 
 
3089
    /**
 
3090
     * Create a directory, making intermediate dirs
 
3091
     * if necessary
 
3092
     */                  
 
3093
    bool createDirectory(const String &dirname);
 
3094
 
 
3095
    /**
 
3096
     * Delete a directory and its children if desired
 
3097
     */
 
3098
    bool removeDirectory(const String &dirName);
 
3099
 
 
3100
    /**
 
3101
     * Copy a file from one name to another. Perform only if needed
 
3102
     */ 
 
3103
    bool copyFile(const String &srcFile, const String &destFile);
 
3104
 
 
3105
    /**
 
3106
     * Tests if the file exists and is a regular file
 
3107
     */ 
 
3108
    bool isRegularFile(const String &fileName);
 
3109
 
 
3110
    /**
 
3111
     * Tests if the file exists and is a directory
 
3112
     */ 
 
3113
    bool isDirectory(const String &fileName);
 
3114
 
 
3115
    /**
 
3116
     * Tests is the modification date of fileA is newer than fileB
 
3117
     */ 
 
3118
    bool isNewerThan(const String &fileA, const String &fileB);
 
3119
 
 
3120
private:
 
3121
 
 
3122
    /**
 
3123
     * replace variable refs like ${a} with their values
 
3124
     */         
 
3125
    bool getSubstitutions(const String &s, String &result);
 
3126
 
 
3127
    int line;
 
3128
 
 
3129
 
 
3130
};
 
3131
 
 
3132
 
 
3133
 
 
3134
 
 
3135
/**
 
3136
 *  Print a printf()-like formatted error message
 
3137
 */
 
3138
void MakeBase::error(const char *fmt, ...)
 
3139
{
 
3140
    va_list args;
 
3141
    va_start(args,fmt);
 
3142
    fprintf(stderr, "Make error line %d: ", line);
 
3143
    vfprintf(stderr, fmt, args);
 
3144
    fprintf(stderr, "\n");
 
3145
    va_end(args) ;
 
3146
}
 
3147
 
 
3148
 
 
3149
 
 
3150
/**
 
3151
 *  Print a printf()-like formatted trace message
 
3152
 */
 
3153
void MakeBase::status(const char *fmt, ...)
 
3154
{
 
3155
    va_list args;
 
3156
    va_start(args,fmt);
 
3157
    //fprintf(stdout, " ");
 
3158
    vfprintf(stdout, fmt, args);
 
3159
    fprintf(stdout, "\n");
 
3160
    va_end(args) ;
 
3161
}
 
3162
 
 
3163
 
 
3164
 
 
3165
/**
 
3166
 *  Resolve another path relative to this one
 
3167
 */
 
3168
String MakeBase::resolve(const String &otherPath)
 
3169
{
 
3170
    URI otherURI(otherPath);
 
3171
    URI fullURI = uri.resolve(otherURI);
 
3172
    String ret = fullURI.toString();
 
3173
    return ret;
 
3174
}
 
3175
 
 
3176
 
 
3177
/**
 
3178
 *  Print a printf()-like formatted trace message
 
3179
 */
 
3180
void MakeBase::trace(const char *fmt, ...)
 
3181
{
 
3182
    va_list args;
 
3183
    va_start(args,fmt);
 
3184
    fprintf(stdout, "Make: ");
 
3185
    vfprintf(stdout, fmt, args);
 
3186
    fprintf(stdout, "\n");
 
3187
    va_end(args) ;
 
3188
}
 
3189
 
 
3190
 
 
3191
 
 
3192
/**
 
3193
 *  Check if a given string matches a given regex pattern
 
3194
 */
 
3195
bool MakeBase::regexMatch(const String &str, const String &pattern)
 
3196
{
 
3197
    const TRexChar *terror = NULL;
 
3198
    const TRexChar *cpat = pattern.c_str();
 
3199
    TRex *expr = trex_compile(cpat, &terror);
 
3200
    if (!expr)
 
3201
        {
 
3202
        if (!terror)
 
3203
            terror = "undefined";
 
3204
        error("compilation error [%s]!\n", terror);
 
3205
        return false;
 
3206
        } 
 
3207
 
 
3208
    bool ret = true;
 
3209
 
 
3210
    const TRexChar *cstr = str.c_str();
 
3211
    if (trex_match(expr, cstr))
 
3212
        {
 
3213
        ret = true;
 
3214
        }
 
3215
    else
 
3216
        {
 
3217
        ret = false;
 
3218
        }
 
3219
 
 
3220
    trex_free(expr);
 
3221
 
 
3222
    return ret;
 
3223
}
 
3224
 
 
3225
/**
 
3226
 *  Return the suffix, if any, of a file name
 
3227
 */
 
3228
String MakeBase::getSuffix(const String &fname)
 
3229
{
 
3230
    if (fname.size() < 2)
 
3231
        return "";
 
3232
    unsigned int pos = fname.find_last_of('.');
 
3233
    if (pos == fname.npos)
 
3234
        return "";
 
3235
    pos++;
 
3236
    String res = fname.substr(pos, fname.size()-pos);
 
3237
    //trace("suffix:%s", res.c_str()); 
 
3238
    return res;
 
3239
}
 
3240
 
 
3241
 
 
3242
 
 
3243
/**
 
3244
 * Break up a string into substrings delimited the characters
 
3245
 * in delimiters.  Null-length substrings are ignored
 
3246
 */  
 
3247
std::vector<String> MakeBase::tokenize(const String &str,
 
3248
                                const String &delimiters)
 
3249
{
 
3250
 
 
3251
    std::vector<String> res;
 
3252
    char *del = (char *)delimiters.c_str();
 
3253
    String dmp;
 
3254
    for (unsigned int i=0 ; i<str.size() ; i++)
 
3255
        {
 
3256
        char ch = str[i];
 
3257
        char *p = (char *)0;
 
3258
        for (p=del ; *p ; p++)
 
3259
            if (*p == ch)
 
3260
                break;
 
3261
        if (*p)
 
3262
            {
 
3263
            if (dmp.size() > 0)
 
3264
                {
 
3265
                res.push_back(dmp);
 
3266
                dmp.clear();
 
3267
                }
 
3268
            }
 
3269
        else
 
3270
            {
 
3271
            dmp.push_back(ch);
 
3272
            }
 
3273
        }
 
3274
    //Add tail
 
3275
    if (dmp.size() > 0)
 
3276
        {
 
3277
        res.push_back(dmp);
 
3278
        dmp.clear();
 
3279
        }
 
3280
 
 
3281
    return res;
 
3282
}
 
3283
 
 
3284
 
 
3285
 
 
3286
/**
 
3287
 *  replace runs of whitespace with a single space
 
3288
 */
 
3289
String MakeBase::strip(const String &s)
 
3290
{
 
3291
    int len = s.size();
 
3292
    String stripped;
 
3293
    for (int i = 0 ; i<len ; i++)
 
3294
        {
 
3295
        char ch = s[i];
 
3296
        if (isspace(ch))
 
3297
            {
 
3298
            stripped.push_back(' ');
 
3299
            for ( ; i<len ; i++)
 
3300
                {
 
3301
                ch = s[i];
 
3302
                if (!isspace(ch))
 
3303
                    {
 
3304
                    stripped.push_back(ch);
 
3305
                    break;
 
3306
                    }
 
3307
                }
 
3308
            }
 
3309
        else
 
3310
            {
 
3311
            stripped.push_back(ch);
 
3312
            }
 
3313
        }
 
3314
    return stripped;
 
3315
}
 
3316
 
 
3317
/**
 
3318
 *  remove leading whitespace from each line
 
3319
 */
 
3320
String MakeBase::leftJustify(const String &s)
 
3321
{
 
3322
    String out;
 
3323
    int len = s.size();
 
3324
    for (int i = 0 ; i<len ; )
 
3325
        {
 
3326
        char ch;
 
3327
        //Skip to first visible character
 
3328
        while (i<len)
 
3329
            {
 
3330
            ch = s[i];
 
3331
            if (ch == '\n' || ch == '\r'
 
3332
              || !isspace(ch))
 
3333
                  break;
 
3334
            i++;
 
3335
            }
 
3336
        //Copy the rest of the line
 
3337
        while (i<len)
 
3338
            {
 
3339
            ch = s[i];
 
3340
            if (ch == '\n' || ch == '\r')
 
3341
                {
 
3342
                if (ch != '\r')
 
3343
                    out.push_back('\n');
 
3344
                i++;
 
3345
                break;
 
3346
                }
 
3347
            else
 
3348
                {
 
3349
                out.push_back(ch);
 
3350
                }
 
3351
            i++;
 
3352
            }
 
3353
        }
 
3354
    return out;
 
3355
}
 
3356
 
 
3357
 
 
3358
/**
 
3359
 *  Removes whitespace from beginning and end of a string
 
3360
 */
 
3361
String MakeBase::trim(const String &s)
 
3362
{
 
3363
    if (s.size() < 1)
 
3364
        return s;
 
3365
    
 
3366
    //Find first non-ws char
 
3367
    unsigned int begin = 0;
 
3368
    for ( ; begin < s.size() ; begin++)
 
3369
        {
 
3370
        if (!isspace(s[begin]))
 
3371
            break;
 
3372
        }
 
3373
 
 
3374
    //Find first non-ws char, going in reverse
 
3375
    unsigned int end = s.size() - 1;
 
3376
    for ( ; end > begin ; end--)
 
3377
        {
 
3378
        if (!isspace(s[end]))
 
3379
            break;
 
3380
        }
 
3381
    //trace("begin:%d  end:%d", begin, end);
 
3382
 
 
3383
    String res = s.substr(begin, end-begin+1);
 
3384
    return res;
 
3385
}
 
3386
 
 
3387
 
 
3388
/**
 
3389
 *  Return a lower case version of the given string
 
3390
 */
 
3391
String MakeBase::toLower(const String &s)
 
3392
{
 
3393
    if (s.size()==0)
 
3394
        return s;
 
3395
 
 
3396
    String ret;
 
3397
    for(unsigned int i=0; i<s.size() ; i++)
 
3398
        {
 
3399
        ret.push_back(tolower(s[i]));
 
3400
        }
 
3401
    return ret;
 
3402
}
 
3403
 
 
3404
 
 
3405
/**
 
3406
 * Return the native format of the canonical
 
3407
 * path which we store
 
3408
 */
 
3409
String MakeBase::getNativePath(const String &path)
 
3410
{
 
3411
#ifdef __WIN32__
 
3412
    String npath;
 
3413
    unsigned int firstChar = 0;
 
3414
    if (path.size() >= 3)
 
3415
        {
 
3416
        if (path[0] == '/' &&
 
3417
            isalpha(path[1]) &&
 
3418
            path[2] == ':')
 
3419
            firstChar++;
 
3420
        }
 
3421
    for (unsigned int i=firstChar ; i<path.size() ; i++)
 
3422
        {
 
3423
        char ch = path[i];
 
3424
        if (ch == '/')
 
3425
            npath.push_back('\\');
 
3426
        else
 
3427
            npath.push_back(ch);
 
3428
        }
 
3429
    return npath;
 
3430
#else
 
3431
    return path;
 
3432
#endif
 
3433
}
 
3434
 
 
3435
 
 
3436
#ifdef __WIN32__
 
3437
#include <tchar.h>
 
3438
 
 
3439
static String win32LastError()
 
3440
{
 
3441
 
 
3442
    DWORD dw = GetLastError(); 
 
3443
 
 
3444
    LPVOID str;
 
3445
    FormatMessage(
 
3446
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
 
3447
        FORMAT_MESSAGE_FROM_SYSTEM,
 
3448
        NULL,
 
3449
        dw,
 
3450
        0,
 
3451
        (LPTSTR) &str,
 
3452
        0, NULL );
 
3453
    LPTSTR p = _tcschr((const char *)str, _T('\r'));
 
3454
    if(p != NULL)
 
3455
        { // lose CRLF
 
3456
        *p = _T('\0');
 
3457
        }
 
3458
    String ret = (char *)str;
 
3459
    LocalFree(str);
 
3460
 
 
3461
    return ret;
 
3462
}
 
3463
#endif
 
3464
 
 
3465
 
 
3466
 
 
3467
/**
 
3468
 * Execute a system call, using pipes to send data to the
 
3469
 * program's stdin,  and reading stdout and stderr.
 
3470
 */
 
3471
bool MakeBase::executeCommand(const String &command,
 
3472
                              const String &inbuf,
 
3473
                              String &outbuf,
 
3474
                              String &errbuf)
 
3475
{
 
3476
 
 
3477
    status("============ cmd ============\n%s\n=============================",
 
3478
                command.c_str());
 
3479
 
 
3480
    outbuf.clear();
 
3481
    errbuf.clear();
 
3482
    
 
3483
#ifdef __WIN32__
 
3484
 
 
3485
    /*
 
3486
    I really hate having win32 code in this program, but the
 
3487
    read buffer in command.com and cmd.exe are just too small
 
3488
    for the large commands we need for compiling and linking.
 
3489
    */
 
3490
 
 
3491
    bool ret = true;
 
3492
 
 
3493
    //# Allocate a separate buffer for safety
 
3494
    char *paramBuf = new char[command.size() + 1];
 
3495
    if (!paramBuf)
 
3496
       {
 
3497
       error("executeCommand cannot allocate command buffer");
 
3498
       return false;
 
3499
       }
 
3500
    strcpy(paramBuf, (char *)command.c_str());
 
3501
 
 
3502
    //# Go to http://msdn2.microsoft.com/en-us/library/ms682499.aspx
 
3503
    //# to see how Win32 pipes work
 
3504
 
 
3505
    //# Create pipes
 
3506
    SECURITY_ATTRIBUTES saAttr; 
 
3507
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
 
3508
    saAttr.bInheritHandle = TRUE; 
 
3509
    saAttr.lpSecurityDescriptor = NULL; 
 
3510
    HANDLE stdinRead,  stdinWrite;
 
3511
    HANDLE stdoutRead, stdoutWrite;
 
3512
    HANDLE stderrRead, stderrWrite;
 
3513
    if (!CreatePipe(&stdinRead, &stdinWrite, &saAttr, 0))
 
3514
        {
 
3515
        error("executeProgram: could not create pipe");
 
3516
        delete[] paramBuf;
 
3517
        return false;
 
3518
        } 
 
3519
    SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0);
 
3520
    if (!CreatePipe(&stdoutRead, &stdoutWrite, &saAttr, 0))
 
3521
        {
 
3522
        error("executeProgram: could not create pipe");
 
3523
        delete[] paramBuf;
 
3524
        return false;
 
3525
        } 
 
3526
    SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0);
 
3527
    if (!CreatePipe(&stderrRead, &stderrWrite, &saAttr, 0))
 
3528
        {
 
3529
        error("executeProgram: could not create pipe");
 
3530
        delete[] paramBuf;
 
3531
        return false;
 
3532
        } 
 
3533
    SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0);
 
3534
 
 
3535
    // Create the process
 
3536
    STARTUPINFO siStartupInfo;
 
3537
    PROCESS_INFORMATION piProcessInfo;
 
3538
    memset(&siStartupInfo, 0, sizeof(siStartupInfo));
 
3539
    memset(&piProcessInfo, 0, sizeof(piProcessInfo));
 
3540
    siStartupInfo.cb = sizeof(siStartupInfo);
 
3541
    siStartupInfo.hStdError   =  stderrWrite;
 
3542
    siStartupInfo.hStdOutput  =  stdoutWrite;
 
3543
    siStartupInfo.hStdInput   =  stdinRead;
 
3544
    siStartupInfo.dwFlags    |=  STARTF_USESTDHANDLES;
 
3545
   
 
3546
    if (!CreateProcess(NULL, paramBuf, NULL, NULL, true,
 
3547
                0, NULL, NULL, &siStartupInfo,
 
3548
                &piProcessInfo))
 
3549
        {
 
3550
        error("executeCommand : could not create process : %s",
 
3551
                    win32LastError().c_str());
 
3552
        ret = false;
 
3553
        }
 
3554
 
 
3555
    delete[] paramBuf;
 
3556
 
 
3557
    DWORD bytesWritten;
 
3558
    if (inbuf.size()>0 &&
 
3559
        !WriteFile(stdinWrite, inbuf.c_str(), inbuf.size(), 
 
3560
               &bytesWritten, NULL))
 
3561
        {
 
3562
        error("executeCommand: could not write to pipe");
 
3563
        return false;
 
3564
        }    
 
3565
    if (!CloseHandle(stdinWrite))
 
3566
        {          
 
3567
        error("executeCommand: could not close write pipe");
 
3568
        return false;
 
3569
        }
 
3570
    if (!CloseHandle(stdoutWrite))
 
3571
        {
 
3572
        error("executeCommand: could not close read pipe");
 
3573
        return false;
 
3574
        }
 
3575
    if (!CloseHandle(stderrWrite))
 
3576
        {
 
3577
        error("executeCommand: could not close read pipe");
 
3578
        return false;
 
3579
        }
 
3580
 
 
3581
    bool lastLoop = false;
 
3582
    while (true)
 
3583
        {
 
3584
        DWORD avail;
 
3585
        DWORD bytesRead;
 
3586
        char readBuf[4096];
 
3587
 
 
3588
        //trace("## stderr");
 
3589
        PeekNamedPipe(stderrRead, NULL, 0, NULL, &avail, NULL);
 
3590
        if (avail > 0)
 
3591
            {
 
3592
            bytesRead = 0;
 
3593
            if (avail>4096) avail = 4096;
 
3594
            ReadFile(stderrRead, readBuf, avail, &bytesRead, NULL);
 
3595
            if (bytesRead > 0)
 
3596
                {
 
3597
                for (unsigned int i=0 ; i<bytesRead ; i++)
 
3598
                    errbuf.push_back(readBuf[i]);
 
3599
                }
 
3600
            }
 
3601
 
 
3602
        //trace("## stdout");
 
3603
        PeekNamedPipe(stdoutRead, NULL, 0, NULL, &avail, NULL);
 
3604
        if (avail > 0)
 
3605
            {
 
3606
            bytesRead = 0;
 
3607
            if (avail>4096) avail = 4096;
 
3608
            ReadFile(stdoutRead, readBuf, avail, &bytesRead, NULL);
 
3609
            if (bytesRead > 0)
 
3610
                {
 
3611
                for (unsigned int i=0 ; i<bytesRead ; i++)
 
3612
                    outbuf.push_back(readBuf[i]);
 
3613
                }
 
3614
            }
 
3615
            
 
3616
        //Was this the final check after program done?
 
3617
        if (lastLoop)
 
3618
            break;
 
3619
 
 
3620
        DWORD exitCode;
 
3621
        GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
 
3622
        if (exitCode != STILL_ACTIVE)
 
3623
            lastLoop = true;
 
3624
 
 
3625
        Sleep(10);
 
3626
        }    
 
3627
    //trace("outbuf:%s", outbuf.c_str());
 
3628
    if (!CloseHandle(stdoutRead))
 
3629
        {
 
3630
        error("executeCommand: could not close read pipe");
 
3631
        return false;
 
3632
        }
 
3633
    if (!CloseHandle(stderrRead))
 
3634
        {
 
3635
        error("executeCommand: could not close read pipe");
 
3636
        return false;
 
3637
        }
 
3638
 
 
3639
    DWORD exitCode;
 
3640
    GetExitCodeProcess(piProcessInfo.hProcess, &exitCode);
 
3641
    //trace("exit code:%d", exitCode);
 
3642
    if (exitCode != 0)
 
3643
        {
 
3644
        ret = false;
 
3645
        }
 
3646
    
 
3647
    CloseHandle(piProcessInfo.hProcess);
 
3648
    CloseHandle(piProcessInfo.hThread);
 
3649
 
 
3650
    return ret;
 
3651
 
 
3652
#else //do it unix-style
 
3653
 
 
3654
    String s;
 
3655
    FILE *f = popen(command.c_str(), "r");
 
3656
    int errnum = 0;
 
3657
    if (f)
 
3658
        {
 
3659
        while (true)
 
3660
            {
 
3661
            int ch = fgetc(f);
 
3662
            if (ch < 0)
 
3663
                break;
 
3664
            s.push_back((char)ch);
 
3665
            }
 
3666
        errnum = pclose(f);
 
3667
        }
 
3668
    outbuf = s;
 
3669
    if (errnum != 0)
 
3670
        {
 
3671
        error("exec of command '%s' failed : %s",
 
3672
             command.c_str(), strerror(errno));
 
3673
        return false;
 
3674
        }
 
3675
    else
 
3676
        return true;
 
3677
 
 
3678
#endif
 
3679
 
3680
 
 
3681
 
 
3682
 
 
3683
 
 
3684
bool MakeBase::listDirectories(const String &baseName,
 
3685
                              const String &dirName,
 
3686
                              std::vector<String> &res)
 
3687
{
 
3688
    res.push_back(dirName);
 
3689
    String fullPath = baseName;
 
3690
    if (dirName.size()>0)
 
3691
        {
 
3692
        fullPath.append("/");
 
3693
        fullPath.append(dirName);
 
3694
        }
 
3695
    DIR *dir = opendir(fullPath.c_str());
 
3696
    while (true)
 
3697
        {
 
3698
        struct dirent *de = readdir(dir);
 
3699
        if (!de)
 
3700
            break;
 
3701
 
 
3702
        //Get the directory member name
 
3703
        String s = de->d_name;
 
3704
        if (s.size() == 0 || s[0] == '.')
 
3705
            continue;
 
3706
        String childName = dirName;
 
3707
        childName.append("/");
 
3708
        childName.append(s);
 
3709
 
 
3710
        String fullChildPath = baseName;
 
3711
        fullChildPath.append("/");
 
3712
        fullChildPath.append(childName);
 
3713
        struct stat finfo;
 
3714
        String childNative = getNativePath(fullChildPath);
 
3715
        if (stat(childNative.c_str(), &finfo)<0)
 
3716
            {
 
3717
            error("cannot stat file:%s", childNative.c_str());
 
3718
            }
 
3719
        else if (S_ISDIR(finfo.st_mode))
 
3720
            {
 
3721
            //trace("directory: %s", childName.c_str());
 
3722
            if (!listDirectories(baseName, childName, res))
 
3723
                return false;
 
3724
            }
 
3725
        }
 
3726
    closedir(dir);
 
3727
 
 
3728
    return true;
 
3729
}
 
3730
 
 
3731
 
 
3732
bool MakeBase::listFiles(const String &baseDir,
 
3733
                         const String &dirName,
 
3734
                         std::vector<String> &res)
 
3735
{
 
3736
    String fullDir = baseDir;
 
3737
    if (dirName.size()>0)
 
3738
        {
 
3739
        fullDir.append("/");
 
3740
        fullDir.append(dirName);
 
3741
        }
 
3742
    String dirNative = getNativePath(fullDir);
 
3743
 
 
3744
    std::vector<String> subdirs;
 
3745
    DIR *dir = opendir(dirNative.c_str());
 
3746
    if (!dir)
 
3747
        {
 
3748
        error("Could not open directory %s : %s",
 
3749
              dirNative.c_str(), strerror(errno));
 
3750
        return false;
 
3751
        }
 
3752
    while (true)
 
3753
        {
 
3754
        struct dirent *de = readdir(dir);
 
3755
        if (!de)
 
3756
            break;
 
3757
 
 
3758
        //Get the directory member name
 
3759
        String s = de->d_name;
 
3760
        if (s.size() == 0 || s[0] == '.')
 
3761
            continue;
 
3762
        String childName;
 
3763
        if (dirName.size()>0)
 
3764
            {
 
3765
            childName.append(dirName);
 
3766
            childName.append("/");
 
3767
            }
 
3768
        childName.append(s);
 
3769
        String fullChild = baseDir;
 
3770
        fullChild.append("/");
 
3771
        fullChild.append(childName);
 
3772
        
 
3773
        if (isDirectory(fullChild))
 
3774
            {
 
3775
            //trace("directory: %s", childName.c_str());
 
3776
            if (!listFiles(baseDir, childName, res))
 
3777
                return false;
 
3778
            continue;
 
3779
            }
 
3780
        else if (!isRegularFile(fullChild))
 
3781
            {
 
3782
            error("unknown file:%s", childName.c_str());
 
3783
            return false;
 
3784
            }
 
3785
 
 
3786
       //all done!
 
3787
        res.push_back(childName);
 
3788
 
 
3789
        }
 
3790
    closedir(dir);
 
3791
 
 
3792
    return true;
 
3793
}
 
3794
 
 
3795
 
 
3796
bool MakeBase::listFiles(MakeBase &propRef, FileSet &fileSet)
 
3797
{
 
3798
    String baseDir = propRef.resolve(fileSet.getDirectory());
 
3799
    std::vector<String> fileList;
 
3800
    if (!listFiles(baseDir, "", fileList))
 
3801
        return false;
 
3802
 
 
3803
    std::vector<String> includes = fileSet.getIncludes();
 
3804
    std::vector<String> excludes = fileSet.getExcludes();
 
3805
 
 
3806
    std::vector<String> incs;
 
3807
    std::vector<String>::iterator iter;
 
3808
 
 
3809
    std::sort(fileList.begin(), fileList.end());
 
3810
 
 
3811
    //If there are <includes>, then add files to the output
 
3812
    //in the order of the include list
 
3813
    if (includes.size()==0)
 
3814
        incs = fileList;
 
3815
    else
 
3816
        {
 
3817
        for (iter = includes.begin() ; iter != includes.end() ; iter++)
 
3818
            {
 
3819
            String pattern = *iter;
 
3820
            std::vector<String>::iterator siter;
 
3821
            for (siter = fileList.begin() ; siter != fileList.end() ; siter++)
 
3822
                {
 
3823
                String s = *siter;
 
3824
                if (regexMatch(s, pattern))
 
3825
                    {
 
3826
                    //trace("INCLUDED:%s", s.c_str());
 
3827
                    incs.push_back(s);
 
3828
                    }
 
3829
                }
 
3830
            }
 
3831
        }
 
3832
 
 
3833
    //Now trim off the <excludes>
 
3834
    std::vector<String> res;
 
3835
    for (iter = incs.begin() ; iter != incs.end() ; iter++)
 
3836
        {
 
3837
        String s = *iter;
 
3838
        bool skipme = false;
 
3839
        std::vector<String>::iterator siter;
 
3840
        for (siter = excludes.begin() ; siter != excludes.end() ; siter++)
 
3841
            {
 
3842
            String pattern = *siter;
 
3843
            if (regexMatch(s, pattern))
 
3844
                {
 
3845
                //trace("EXCLUDED:%s", s.c_str());
 
3846
                skipme = true;
 
3847
                break;
 
3848
                }
 
3849
            }
 
3850
        if (!skipme)
 
3851
            res.push_back(s);
 
3852
        }
 
3853
        
 
3854
    fileSet.setFiles(res);
 
3855
 
 
3856
    return true;
 
3857
}
 
3858
 
 
3859
 
 
3860
 
 
3861
 
 
3862
 
 
3863
bool MakeBase::getSubstitutions(const String &str, String &result)
 
3864
{
 
3865
    String s = trim(str);
 
3866
    int len = (int)s.size();
 
3867
    String val;
 
3868
    for (int i=0 ; i<len ; i++)
 
3869
        {
 
3870
        char ch = s[i];
 
3871
        if (ch == '$' && s[i+1] == '{')
 
3872
            {
 
3873
            String varname;
 
3874
            int j = i+2;
 
3875
            for ( ; j<len ; j++)
 
3876
                {
 
3877
                ch = s[j];
 
3878
                if (ch == '$' && s[j+1] == '{')
 
3879
                    {
 
3880
                    error("attribute %s cannot have nested variable references",
 
3881
                           s.c_str());
 
3882
                    return false;
 
3883
                    }
 
3884
                else if (ch == '}')
 
3885
                    {
 
3886
                    std::map<String, String>::iterator iter;
 
3887
                    varname = trim(varname);
 
3888
                    if (envPrefix.size() > 0 && varname.compare(0, envPrefix.size(), envPrefix) == 0)
 
3889
                        {
 
3890
                        varname = varname.substr(envPrefix.size());
 
3891
                        char *envstr = getenv(varname.c_str());
 
3892
                        if (!envstr)
 
3893
                            {
 
3894
                            error("environment variable '%s' not defined", varname.c_str());
 
3895
                            return false;
 
3896
                            }
 
3897
                        val.append(envstr);
 
3898
                        }
 
3899
                    else
 
3900
                        {
 
3901
                        iter = properties.find(varname);
 
3902
                        if (iter != properties.end())
 
3903
                            {
 
3904
                            val.append(iter->second);
 
3905
                            }
 
3906
                        else
 
3907
                            {
 
3908
                            error("property ${%s} not found", varname.c_str());
 
3909
                            return false;
 
3910
                            }
 
3911
                        }
 
3912
                    break;
 
3913
                    }
 
3914
                else
 
3915
                    {
 
3916
                    varname.push_back(ch);
 
3917
                    }
 
3918
                }
 
3919
            i = j;
 
3920
            }
 
3921
        else
 
3922
            {
 
3923
            val.push_back(ch);
 
3924
            }
 
3925
        }
 
3926
    result = val;
 
3927
    return true;
 
3928
}
 
3929
 
 
3930
 
 
3931
bool MakeBase::getAttribute(Element *elem, const String &name,
 
3932
                                    String &result)
 
3933
{
 
3934
    String s = elem->getAttribute(name);
 
3935
    return getSubstitutions(s, result);
 
3936
}
 
3937
 
 
3938
 
 
3939
bool MakeBase::getValue(Element *elem, String &result)
 
3940
{
 
3941
    String s = elem->getValue();
 
3942
    //Replace all runs of whitespace with a single space
 
3943
    return getSubstitutions(s, result);
 
3944
}
 
3945
 
 
3946
 
 
3947
/**
 
3948
 * Turn 'true' and 'false' into boolean values
 
3949
 */             
 
3950
bool MakeBase::getBool(const String &str, bool &val)
 
3951
{
 
3952
    if (str == "true")
 
3953
        val = true;
 
3954
    else if (str == "false")
 
3955
        val = false;
 
3956
    else
 
3957
        {
 
3958
        error("expected 'true' or 'false'.  found '%s'", str.c_str());
 
3959
        return false;
 
3960
        }
 
3961
    return true;
 
3962
}
 
3963
 
 
3964
 
 
3965
 
 
3966
 
 
3967
/**
 
3968
 * Parse a <patternset> entry
 
3969
 */  
 
3970
bool MakeBase::parsePatternSet(Element *elem,
 
3971
                          MakeBase &propRef,
 
3972
                          std::vector<String> &includes,
 
3973
                          std::vector<String> &excludes
 
3974
                          )
 
3975
{
 
3976
    std::vector<Element *> children  = elem->getChildren();
 
3977
    for (unsigned int i=0 ; i<children.size() ; i++)
 
3978
        {
 
3979
        Element *child = children[i];
 
3980
        String tagName = child->getName();
 
3981
        if (tagName == "exclude")
 
3982
            {
 
3983
            String fname;
 
3984
            if (!propRef.getAttribute(child, "name", fname))
 
3985
                return false;
 
3986
            //trace("EXCLUDE: %s", fname.c_str());
 
3987
            excludes.push_back(fname);
 
3988
            }
 
3989
        else if (tagName == "include")
 
3990
            {
 
3991
            String fname;
 
3992
            if (!propRef.getAttribute(child, "name", fname))
 
3993
                return false;
 
3994
            //trace("INCLUDE: %s", fname.c_str());
 
3995
            includes.push_back(fname);
 
3996
            }
 
3997
        }
 
3998
 
 
3999
    return true;
 
4000
}
 
4001
 
 
4002
 
 
4003
 
 
4004
 
 
4005
/**
 
4006
 * Parse a <fileset> entry, and determine which files
 
4007
 * should be included
 
4008
 */  
 
4009
bool MakeBase::parseFileSet(Element *elem,
 
4010
                          MakeBase &propRef,
 
4011
                          FileSet &fileSet)
 
4012
{
 
4013
    String name = elem->getName();
 
4014
    if (name != "fileset")
 
4015
        {
 
4016
        error("expected <fileset>");
 
4017
        return false;
 
4018
        }
 
4019
 
 
4020
 
 
4021
    std::vector<String> includes;
 
4022
    std::vector<String> excludes;
 
4023
 
 
4024
    //A fileset has one implied patternset
 
4025
    if (!parsePatternSet(elem, propRef, includes, excludes))
 
4026
        {
 
4027
        return false;
 
4028
        }
 
4029
    //Look for child tags, including more patternsets
 
4030
    std::vector<Element *> children  = elem->getChildren();
 
4031
    for (unsigned int i=0 ; i<children.size() ; i++)
 
4032
        {
 
4033
        Element *child = children[i];
 
4034
        String tagName = child->getName();
 
4035
        if (tagName == "patternset")
 
4036
            {
 
4037
            if (!parsePatternSet(child, propRef, includes, excludes))
 
4038
                {
 
4039
                return false;
 
4040
                }
 
4041
            }
 
4042
        }
 
4043
 
 
4044
    String dir;
 
4045
    //Now do the stuff
 
4046
    //Get the base directory for reading file names
 
4047
    if (!propRef.getAttribute(elem, "dir", dir))
 
4048
        return false;
 
4049
 
 
4050
    fileSet.setDirectory(dir);
 
4051
    fileSet.setIncludes(includes);
 
4052
    fileSet.setExcludes(excludes);
 
4053
    
 
4054
    /*
 
4055
    std::vector<String> fileList;
 
4056
    if (dir.size() > 0)
 
4057
        {
 
4058
        String baseDir = propRef.resolve(dir);
 
4059
        if (!listFiles(baseDir, "", includes, excludes, fileList))
 
4060
            return false;
 
4061
        }
 
4062
    std::sort(fileList.begin(), fileList.end());
 
4063
    result = fileList;
 
4064
    */
 
4065
 
 
4066
    
 
4067
    /*
 
4068
    for (unsigned int i=0 ; i<result.size() ; i++)
 
4069
        {
 
4070
        trace("RES:%s", result[i].c_str());
 
4071
        }
 
4072
    */
 
4073
 
 
4074
    
 
4075
    return true;
 
4076
}
 
4077
 
 
4078
 
 
4079
 
 
4080
/**
 
4081
 * Create a directory, making intermediate dirs
 
4082
 * if necessary
 
4083
 */                  
 
4084
bool MakeBase::createDirectory(const String &dirname)
 
4085
{
 
4086
    //trace("## createDirectory: %s", dirname.c_str());
 
4087
    //## first check if it exists
 
4088
    struct stat finfo;
 
4089
    String nativeDir = getNativePath(dirname);
 
4090
    char *cnative = (char *) nativeDir.c_str();
 
4091
#ifdef __WIN32__
 
4092
    if (strlen(cnative)==2 && cnative[1]==':')
 
4093
        return true;
 
4094
#endif
 
4095
    if (stat(cnative, &finfo)==0)
 
4096
        {
 
4097
        if (!S_ISDIR(finfo.st_mode))
 
4098
            {
 
4099
            error("mkdir: file %s exists but is not a directory",
 
4100
                  cnative);
 
4101
            return false;
 
4102
            }
 
4103
        else //exists
 
4104
            {
 
4105
            return true;
 
4106
            }
 
4107
        }
 
4108
 
 
4109
    //## 2: pull off the last path segment, if any,
 
4110
    //## to make the dir 'above' this one, if necessary
 
4111
    unsigned int pos = dirname.find_last_of('/');
 
4112
    if (pos>0 && pos != dirname.npos)
 
4113
        {
 
4114
        String subpath = dirname.substr(0, pos);
 
4115
        //A letter root (c:) ?
 
4116
        if (!createDirectory(subpath))
 
4117
            return false;
 
4118
        }
 
4119
        
 
4120
    //## 3: now make
 
4121
#ifdef __WIN32__
 
4122
    if (mkdir(cnative)<0)
 
4123
#else
 
4124
    if (mkdir(cnative, S_IRWXU | S_IRWXG | S_IRWXO)<0)
 
4125
#endif
 
4126
        {
 
4127
        error("cannot make directory '%s' : %s",
 
4128
                 cnative, strerror(errno));
 
4129
        return false;
 
4130
        }
 
4131
        
 
4132
    return true;
 
4133
}
 
4134
 
 
4135
 
 
4136
/**
 
4137
 * Remove a directory recursively
 
4138
 */ 
 
4139
bool MakeBase::removeDirectory(const String &dirName)
 
4140
{
 
4141
    char *dname = (char *)dirName.c_str();
 
4142
 
 
4143
    DIR *dir = opendir(dname);
 
4144
    if (!dir)
 
4145
        {
 
4146
        //# Let this fail nicely.
 
4147
        return true;
 
4148
        //error("error opening directory %s : %s", dname, strerror(errno));
 
4149
        //return false;
 
4150
        }
 
4151
    
 
4152
    while (true)
 
4153
        {
 
4154
        struct dirent *de = readdir(dir);
 
4155
        if (!de)
 
4156
            break;
 
4157
 
 
4158
        //Get the directory member name
 
4159
        String s = de->d_name;
 
4160
        if (s.size() == 0 || s[0] == '.')
 
4161
            continue;
 
4162
        String childName;
 
4163
        if (dirName.size() > 0)
 
4164
            {
 
4165
            childName.append(dirName);
 
4166
            childName.append("/");
 
4167
            }
 
4168
        childName.append(s);
 
4169
 
 
4170
 
 
4171
        struct stat finfo;
 
4172
        String childNative = getNativePath(childName);
 
4173
        char *cnative = (char *)childNative.c_str();
 
4174
        if (stat(cnative, &finfo)<0)
 
4175
            {
 
4176
            error("cannot stat file:%s", cnative);
 
4177
            }
 
4178
        else if (S_ISDIR(finfo.st_mode))
 
4179
            {
 
4180
            //trace("DEL dir: %s", childName.c_str());
 
4181
            if (!removeDirectory(childName))
 
4182
                {
 
4183
                return false;
 
4184
                }
 
4185
            }
 
4186
        else if (!S_ISREG(finfo.st_mode))
 
4187
            {
 
4188
            //trace("not regular: %s", cnative);
 
4189
            }
 
4190
        else
 
4191
            {
 
4192
            //trace("DEL file: %s", childName.c_str());
 
4193
            if (remove(cnative)<0)
 
4194
                {
 
4195
                error("error deleting %s : %s",
 
4196
                     cnative, strerror(errno));
 
4197
                return false;
 
4198
                }
 
4199
            }
 
4200
        }
 
4201
    closedir(dir);
 
4202
 
 
4203
    //Now delete the directory
 
4204
    String native = getNativePath(dirName);
 
4205
    if (rmdir(native.c_str())<0)
 
4206
        {
 
4207
        error("could not delete directory %s : %s",
 
4208
            native.c_str() , strerror(errno));
 
4209
        return false;
 
4210
        }
 
4211
 
 
4212
    return true;
 
4213
    
 
4214
}
 
4215
 
 
4216
 
 
4217
/**
 
4218
 * Copy a file from one name to another. Perform only if needed
 
4219
 */ 
 
4220
bool MakeBase::copyFile(const String &srcFile, const String &destFile)
 
4221
{
 
4222
    //# 1 Check up-to-date times
 
4223
    String srcNative = getNativePath(srcFile);
 
4224
    struct stat srcinfo;
 
4225
    if (stat(srcNative.c_str(), &srcinfo)<0)
 
4226
        {
 
4227
        error("source file %s for copy does not exist",
 
4228
                 srcNative.c_str());
 
4229
        return false;
 
4230
        }
 
4231
 
 
4232
    String destNative = getNativePath(destFile);
 
4233
    struct stat destinfo;
 
4234
    if (stat(destNative.c_str(), &destinfo)==0)
 
4235
        {
 
4236
        if (destinfo.st_mtime >= srcinfo.st_mtime)
 
4237
            return true;
 
4238
        }
 
4239
        
 
4240
    //# 2 prepare a destination directory if necessary
 
4241
    unsigned int pos = destFile.find_last_of('/');
 
4242
    if (pos != destFile.npos)
 
4243
        {
 
4244
        String subpath = destFile.substr(0, pos);
 
4245
        if (!createDirectory(subpath))
 
4246
            return false;
 
4247
        }
 
4248
 
 
4249
    //# 3 do the data copy
 
4250
#ifndef __WIN32__
 
4251
 
 
4252
    FILE *srcf = fopen(srcNative.c_str(), "rb");
 
4253
    if (!srcf)
 
4254
        {
 
4255
        error("copyFile cannot open '%s' for reading", srcNative.c_str());
 
4256
        return false;
 
4257
        }
 
4258
    FILE *destf = fopen(destNative.c_str(), "wb");
 
4259
    if (!destf)
 
4260
        {
 
4261
        error("copyFile cannot open %s for writing", srcNative.c_str());
 
4262
        return false;
 
4263
        }
 
4264
 
 
4265
    while (!feof(srcf))
 
4266
        {
 
4267
        int ch = fgetc(srcf);
 
4268
        if (ch<0)
 
4269
            break;
 
4270
        fputc(ch, destf);
 
4271
        }
 
4272
 
 
4273
    fclose(destf);
 
4274
    fclose(srcf);
 
4275
 
 
4276
#else
 
4277
    
 
4278
    if (!CopyFile(srcNative.c_str(), destNative.c_str(), false))
 
4279
        {
 
4280
        error("copyFile from %s to %s failed",
 
4281
             srcNative.c_str(), destNative.c_str());
 
4282
        return false;
 
4283
        }
 
4284
        
 
4285
#endif /* __WIN32__ */
 
4286
 
 
4287
 
 
4288
    return true;
 
4289
}
 
4290
 
 
4291
 
 
4292
 
 
4293
/**
 
4294
 * Tests if the file exists and is a regular file
 
4295
 */ 
 
4296
bool MakeBase::isRegularFile(const String &fileName)
 
4297
{
 
4298
    String native = getNativePath(fileName);
 
4299
    struct stat finfo;
 
4300
    
 
4301
    //Exists?
 
4302
    if (stat(native.c_str(), &finfo)<0)
 
4303
        return false;
 
4304
 
 
4305
 
 
4306
    //check the file mode
 
4307
    if (!S_ISREG(finfo.st_mode))
 
4308
        return false;
 
4309
 
 
4310
    return true;
 
4311
}
 
4312
 
 
4313
/**
 
4314
 * Tests if the file exists and is a directory
 
4315
 */ 
 
4316
bool MakeBase::isDirectory(const String &fileName)
 
4317
{
 
4318
    String native = getNativePath(fileName);
 
4319
    struct stat finfo;
 
4320
    
 
4321
    //Exists?
 
4322
    if (stat(native.c_str(), &finfo)<0)
 
4323
        return false;
 
4324
 
 
4325
 
 
4326
    //check the file mode
 
4327
    if (!S_ISDIR(finfo.st_mode))
 
4328
        return false;
 
4329
 
 
4330
    return true;
 
4331
}
 
4332
 
 
4333
 
 
4334
 
 
4335
/**
 
4336
 * Tests is the modification of fileA is newer than fileB
 
4337
 */ 
 
4338
bool MakeBase::isNewerThan(const String &fileA, const String &fileB)
 
4339
{
 
4340
    //trace("isNewerThan:'%s' , '%s'", fileA.c_str(), fileB.c_str());
 
4341
    String nativeA = getNativePath(fileA);
 
4342
    struct stat infoA;
 
4343
    //IF source does not exist, NOT newer
 
4344
    if (stat(nativeA.c_str(), &infoA)<0)
 
4345
        {
 
4346
        return false;
 
4347
        }
 
4348
 
 
4349
    String nativeB = getNativePath(fileB);
 
4350
    struct stat infoB;
 
4351
    //IF dest does not exist, YES, newer
 
4352
    if (stat(nativeB.c_str(), &infoB)<0)
 
4353
        {
 
4354
        return true;
 
4355
        }
 
4356
 
 
4357
    //check the actual times
 
4358
    if (infoA.st_mtime > infoB.st_mtime)
 
4359
        {
 
4360
        return true;
 
4361
        }
 
4362
 
 
4363
    return false;
 
4364
}
 
4365
 
 
4366
 
 
4367
//########################################################################
 
4368
//# P K G    C O N F I G
 
4369
//########################################################################
 
4370
 
 
4371
/**
 
4372
 *
 
4373
 */
 
4374
class PkgConfig : public MakeBase
 
4375
{
 
4376
 
 
4377
public:
 
4378
 
 
4379
    /**
 
4380
     *
 
4381
     */
 
4382
    PkgConfig()
 
4383
        { path="."; init(); }
 
4384
 
 
4385
    /**
 
4386
     *
 
4387
     */
 
4388
    PkgConfig(const PkgConfig &other)
 
4389
        { assign(other); }
 
4390
 
 
4391
    /**
 
4392
     *
 
4393
     */
 
4394
    PkgConfig &operator=(const PkgConfig &other)
 
4395
        { assign(other); return *this; }
 
4396
 
 
4397
    /**
 
4398
     *
 
4399
     */
 
4400
    virtual ~PkgConfig()
 
4401
        { }
 
4402
 
 
4403
    /**
 
4404
     *
 
4405
     */
 
4406
    virtual String getName()
 
4407
        { return name; }
 
4408
 
 
4409
    /**
 
4410
     *
 
4411
     */
 
4412
    virtual String getPath()
 
4413
        { return path; }
 
4414
 
 
4415
    /**
 
4416
     *
 
4417
     */
 
4418
    virtual void setPath(const String &val)
 
4419
        { path = val; }
 
4420
 
 
4421
    /**
 
4422
     *
 
4423
     */
 
4424
    virtual String getPrefix()
 
4425
        { return prefix; }
 
4426
 
 
4427
    /**
 
4428
     *  Allow the user to override the prefix in the file
 
4429
     */
 
4430
    virtual void setPrefix(const String &val)
 
4431
        { prefix = val; }
 
4432
 
 
4433
    /**
 
4434
     *
 
4435
     */
 
4436
    virtual String getDescription()
 
4437
        { return description; }
 
4438
 
 
4439
    /**
 
4440
     *
 
4441
     */
 
4442
    virtual String getCflags()
 
4443
        { return cflags; }
 
4444
 
 
4445
    /**
 
4446
     *
 
4447
     */
 
4448
    virtual String getLibs()
 
4449
        { return libs; }
 
4450
 
 
4451
    /**
 
4452
     *
 
4453
     */
 
4454
    virtual String getAll()
 
4455
        {
 
4456
         String ret = cflags;
 
4457
         ret.append(" ");
 
4458
         ret.append(libs);
 
4459
         return ret;
 
4460
        }
 
4461
 
 
4462
    /**
 
4463
     *
 
4464
     */
 
4465
    virtual String getVersion()
 
4466
        { return version; }
 
4467
 
 
4468
    /**
 
4469
     *
 
4470
     */
 
4471
    virtual int getMajorVersion()
 
4472
        { return majorVersion; }
 
4473
 
 
4474
    /**
 
4475
     *
 
4476
     */
 
4477
    virtual int getMinorVersion()
 
4478
        { return minorVersion; }
 
4479
 
 
4480
    /**
 
4481
     *
 
4482
     */
 
4483
    virtual int getMicroVersion()
 
4484
        { return microVersion; }
 
4485
 
 
4486
    /**
 
4487
     *
 
4488
     */
 
4489
    virtual std::map<String, String> &getAttributes()
 
4490
        { return attrs; }
 
4491
 
 
4492
    /**
 
4493
     *
 
4494
     */
 
4495
    virtual std::vector<String> &getRequireList()
 
4496
        { return requireList; }
 
4497
 
 
4498
    /**
 
4499
     *  Read a file for its details
 
4500
     */         
 
4501
    virtual bool readFile(const String &fileName);
 
4502
 
 
4503
    /**
 
4504
     *  Read a file for its details
 
4505
     */         
 
4506
    virtual bool query(const String &name);
 
4507
 
 
4508
private:
 
4509
 
 
4510
    void init()
 
4511
        {
 
4512
        //do not set path or prefix here
 
4513
        name         = "";
 
4514
        description  = "";
 
4515
        cflags       = "";
 
4516
        libs         = "";
 
4517
        requires     = "";
 
4518
        version      = "";
 
4519
        majorVersion = 0;
 
4520
        minorVersion = 0;
 
4521
        microVersion = 0;
 
4522
        fileName     = "";
 
4523
        attrs.clear();
 
4524
        requireList.clear();
 
4525
        }
 
4526
 
 
4527
    void assign(const PkgConfig &other)
 
4528
        {
 
4529
        name         = other.name;
 
4530
        path         = other.path;
 
4531
        prefix       = other.prefix;
 
4532
        description  = other.description;
 
4533
        cflags       = other.cflags;
 
4534
        libs         = other.libs;
 
4535
        requires     = other.requires;
 
4536
        version      = other.version;
 
4537
        majorVersion = other.majorVersion;
 
4538
        minorVersion = other.minorVersion;
 
4539
        microVersion = other.microVersion;
 
4540
        fileName     = other.fileName;
 
4541
        attrs        = other.attrs;
 
4542
        requireList  = other.requireList;
 
4543
        }
 
4544
 
 
4545
 
 
4546
 
 
4547
    int get(int pos);
 
4548
 
 
4549
    int skipwhite(int pos);
 
4550
 
 
4551
    int getword(int pos, String &ret);
 
4552
 
 
4553
    void parseRequires();
 
4554
 
 
4555
    void parseVersion();
 
4556
 
 
4557
    bool parseLine(const String &lineBuf);
 
4558
 
 
4559
    bool parse(const String &buf);
 
4560
 
 
4561
    void dumpAttrs();
 
4562
 
 
4563
    String name;
 
4564
 
 
4565
    String path;
 
4566
 
 
4567
    String prefix;
 
4568
 
 
4569
    String description;
 
4570
 
 
4571
    String cflags;
 
4572
 
 
4573
    String libs;
 
4574
 
 
4575
    String requires;
 
4576
 
 
4577
    String version;
 
4578
 
 
4579
    int majorVersion;
 
4580
 
 
4581
    int minorVersion;
 
4582
 
 
4583
    int microVersion;
 
4584
 
 
4585
    String fileName;
 
4586
 
 
4587
    std::map<String, String> attrs;
 
4588
 
 
4589
    std::vector<String> requireList;
 
4590
 
 
4591
    char *parsebuf;
 
4592
    int parselen;
 
4593
};
 
4594
 
 
4595
 
 
4596
/**
 
4597
 * Get a character from the buffer at pos.  If out of range,
 
4598
 * return -1 for safety
 
4599
 */
 
4600
int PkgConfig::get(int pos)
 
4601
{
 
4602
    if (pos>parselen)
 
4603
        return -1;
 
4604
    return parsebuf[pos];
 
4605
}
 
4606
 
 
4607
 
 
4608
 
 
4609
/**
 
4610
 *  Skip over all whitespace characters beginning at pos.  Return
 
4611
 *  the position of the first non-whitespace character.
 
4612
 *  Pkg-config is line-oriented, so check for newline
 
4613
 */
 
4614
int PkgConfig::skipwhite(int pos)
 
4615
{
 
4616
    while (pos < parselen)
 
4617
        {
 
4618
        int ch = get(pos);
 
4619
        if (ch < 0)
 
4620
            break;
 
4621
        if (!isspace(ch))
 
4622
            break;
 
4623
        pos++;
 
4624
        }
 
4625
    return pos;
 
4626
}
 
4627
 
 
4628
 
 
4629
/**
 
4630
 *  Parse the buffer beginning at pos, for a word.  Fill
 
4631
 *  'ret' with the result.  Return the position after the
 
4632
 *  word.
 
4633
 */
 
4634
int PkgConfig::getword(int pos, String &ret)
 
4635
{
 
4636
    while (pos < parselen)
 
4637
        {
 
4638
        int ch = get(pos);
 
4639
        if (ch < 0)
 
4640
            break;
 
4641
        if (!isalnum(ch) && ch != '_' && ch != '-'&& ch != '.')
 
4642
            break;
 
4643
        ret.push_back((char)ch);
 
4644
        pos++;
 
4645
        }
 
4646
    return pos;
 
4647
}
 
4648
 
 
4649
void PkgConfig::parseRequires()
 
4650
{
 
4651
    if (requires.size() == 0)
 
4652
        return;
 
4653
    parsebuf = (char *)requires.c_str();
 
4654
    parselen = requires.size();
 
4655
    int pos = 0;
 
4656
    while (pos < parselen)
 
4657
        {
 
4658
        pos = skipwhite(pos);
 
4659
        String val;
 
4660
        int pos2 = getword(pos, val);
 
4661
        if (pos2 == pos)
 
4662
            break;
 
4663
        pos = pos2;
 
4664
        //trace("val %s", val.c_str());
 
4665
        requireList.push_back(val);
 
4666
        }
 
4667
}
 
4668
 
 
4669
static int getint(const String str)
 
4670
{
 
4671
    char *s = (char *)str.c_str();
 
4672
    char *ends = NULL;
 
4673
    long val = strtol(s, &ends, 10);
 
4674
    if (ends == s)
 
4675
        return 0L;
 
4676
    else
 
4677
        return val;
 
4678
}
 
4679
 
 
4680
void PkgConfig::parseVersion()
 
4681
{
 
4682
    if (version.size() == 0)
 
4683
        return;
 
4684
    String s1, s2, s3;
 
4685
    unsigned int pos = 0;
 
4686
    unsigned int pos2 = version.find('.', pos);
 
4687
    if (pos2 == version.npos)
 
4688
        {
 
4689
        s1 = version;
 
4690
        }
 
4691
    else
 
4692
        {
 
4693
        s1 = version.substr(pos, pos2-pos);
 
4694
        pos = pos2;
 
4695
        pos++;
 
4696
        if (pos < version.size())
 
4697
            {
 
4698
            pos2 = version.find('.', pos);
 
4699
            if (pos2 == version.npos)
 
4700
                {
 
4701
                s2 = version.substr(pos, version.size()-pos);
 
4702
                }
 
4703
            else
 
4704
                {
 
4705
                s2 = version.substr(pos, pos2-pos);
 
4706
                pos = pos2;
 
4707
                pos++;
 
4708
                if (pos < version.size())
 
4709
                    s3 = version.substr(pos, pos2-pos);
 
4710
                }
 
4711
            }
 
4712
        }
 
4713
 
 
4714
    majorVersion = getint(s1);
 
4715
    minorVersion = getint(s2);
 
4716
    microVersion = getint(s3);
 
4717
    //trace("version:%d.%d.%d", majorVersion,
 
4718
    //          minorVersion, microVersion );
 
4719
}
 
4720
 
 
4721
 
 
4722
bool PkgConfig::parseLine(const String &lineBuf)
 
4723
{
 
4724
    parsebuf = (char *)lineBuf.c_str();
 
4725
    parselen = lineBuf.size();
 
4726
    int pos = 0;
 
4727
    
 
4728
    while (pos < parselen)
 
4729
        {
 
4730
        String attrName;
 
4731
        pos = skipwhite(pos);
 
4732
        int ch = get(pos);
 
4733
        if (ch == '#')
 
4734
            {
 
4735
            //comment.  eat the rest of the line
 
4736
            while (pos < parselen)
 
4737
                {
 
4738
                ch = get(pos);
 
4739
                if (ch == '\n' || ch < 0)
 
4740
                    break;
 
4741
                pos++;
 
4742
                }
 
4743
            continue;
 
4744
            }
 
4745
        pos = getword(pos, attrName);
 
4746
        if (attrName.size() == 0)
 
4747
            continue;
 
4748
        
 
4749
        pos = skipwhite(pos);
 
4750
        ch = get(pos);
 
4751
        if (ch != ':' && ch != '=')
 
4752
            {
 
4753
            error("expected ':' or '='");
 
4754
            return false;
 
4755
            }
 
4756
        pos++;
 
4757
        pos = skipwhite(pos);
 
4758
        String attrVal;
 
4759
        while (pos < parselen)
 
4760
            {
 
4761
            ch = get(pos);
 
4762
            if (ch == '\n' || ch < 0)
 
4763
                break;
 
4764
            else if (ch == '$' && get(pos+1) == '{')
 
4765
                {
 
4766
                //#  this is a ${substitution}
 
4767
                pos += 2;
 
4768
                String subName;
 
4769
                while (pos < parselen)
 
4770
                    {
 
4771
                    ch = get(pos);
 
4772
                    if (ch < 0)
 
4773
                        {
 
4774
                        error("unterminated substitution");
 
4775
                        return false;
 
4776
                        }
 
4777
                    else if (ch == '}')
 
4778
                        break;
 
4779
                    else
 
4780
                        subName.push_back((char)ch);
 
4781
                    pos++;
 
4782
                    }
 
4783
                //trace("subName:%s %s", subName.c_str(), prefix.c_str());
 
4784
                if (subName == "prefix" && prefix.size()>0)
 
4785
                    {
 
4786
                    attrVal.append(prefix);
 
4787
                    //trace("prefix override:%s", prefix.c_str());
 
4788
                    }
 
4789
                else
 
4790
                    {
 
4791
                    String subVal = attrs[subName];
 
4792
                    //trace("subVal:%s", subVal.c_str());
 
4793
                    attrVal.append(subVal);
 
4794
                    }
 
4795
                }
 
4796
            else
 
4797
                attrVal.push_back((char)ch);
 
4798
            pos++;
 
4799
            }
 
4800
 
 
4801
        attrVal = trim(attrVal);
 
4802
        attrs[attrName] = attrVal;
 
4803
 
 
4804
        String attrNameL = toLower(attrName);
 
4805
 
 
4806
        if (attrNameL == "name")
 
4807
            name = attrVal;
 
4808
        else if (attrNameL == "description")
 
4809
            description = attrVal;
 
4810
        else if (attrNameL == "cflags")
 
4811
            cflags = attrVal;
 
4812
        else if (attrNameL == "libs")
 
4813
            libs = attrVal;
 
4814
        else if (attrNameL == "requires")
 
4815
            requires = attrVal;
 
4816
        else if (attrNameL == "version")
 
4817
            version = attrVal;
 
4818
 
 
4819
        //trace("name:'%s'  value:'%s'",
 
4820
        //      attrName.c_str(), attrVal.c_str());
 
4821
        }
 
4822
 
 
4823
    return true;
 
4824
}
 
4825
 
 
4826
 
 
4827
bool PkgConfig::parse(const String &buf)
 
4828
{
 
4829
    init();
 
4830
 
 
4831
    String line;
 
4832
    int lineNr = 0;
 
4833
    for (unsigned int p=0 ; p<buf.size() ; p++)
 
4834
        {
 
4835
        int ch = buf[p];
 
4836
        if (ch == '\n' || ch == '\r')
 
4837
            {
 
4838
            if (!parseLine(line))
 
4839
                return false;
 
4840
            line.clear();
 
4841
            lineNr++;
 
4842
            }
 
4843
        else
 
4844
            {
 
4845
            line.push_back(ch);
 
4846
            }
 
4847
        }
 
4848
    if (line.size()>0)
 
4849
        {
 
4850
        if (!parseLine(line))
 
4851
            return false;
 
4852
        }
 
4853
 
 
4854
    parseRequires();
 
4855
    parseVersion();
 
4856
 
 
4857
    return true;
 
4858
}
 
4859
 
 
4860
 
 
4861
 
 
4862
 
 
4863
void PkgConfig::dumpAttrs()
 
4864
{
 
4865
    //trace("### PkgConfig attributes for %s", fileName.c_str());
 
4866
    std::map<String, String>::iterator iter;
 
4867
    for (iter=attrs.begin() ; iter!=attrs.end() ; iter++)
 
4868
        {
 
4869
        trace("   %s = %s", iter->first.c_str(), iter->second.c_str());
 
4870
        }
 
4871
}
 
4872
 
 
4873
 
 
4874
bool PkgConfig::readFile(const String &fname)
 
4875
{
 
4876
    fileName = getNativePath(fname);
 
4877
 
 
4878
    FILE *f = fopen(fileName.c_str(), "r");
 
4879
    if (!f)
 
4880
        {
 
4881
        error("cannot open file '%s' for reading", fileName.c_str());
 
4882
        return false;
 
4883
        }
 
4884
    String buf;
 
4885
    while (true)
 
4886
        {
 
4887
        int ch = fgetc(f);
 
4888
        if (ch < 0)
 
4889
            break;
 
4890
        buf.push_back((char)ch);
 
4891
        }
 
4892
    fclose(f);
 
4893
 
 
4894
    //trace("####### File:\n%s", buf.c_str());
 
4895
    if (!parse(buf))
 
4896
        {
 
4897
        return false;
 
4898
        }
 
4899
 
 
4900
    //dumpAttrs();
 
4901
 
 
4902
    return true;
 
4903
}
 
4904
 
 
4905
 
 
4906
 
 
4907
bool PkgConfig::query(const String &pkgName)
 
4908
{
 
4909
    name = pkgName;
 
4910
 
 
4911
    String fname = path;
 
4912
    fname.append("/");
 
4913
    fname.append(name);
 
4914
    fname.append(".pc");
 
4915
 
 
4916
    if (!readFile(fname))
 
4917
        return false;
 
4918
    
 
4919
    return true;
 
4920
}
 
4921
 
 
4922
 
 
4923
 
 
4924
 
 
4925
 
 
4926
//########################################################################
 
4927
//# D E P T O O L
 
4928
//########################################################################
 
4929
 
 
4930
 
 
4931
 
 
4932
/**
 
4933
 *  Class which holds information for each file.
 
4934
 */
 
4935
class FileRec
 
4936
{
 
4937
public:
 
4938
 
 
4939
    typedef enum
 
4940
        {
 
4941
        UNKNOWN,
 
4942
        CFILE,
 
4943
        HFILE,
 
4944
        OFILE
 
4945
        } FileType;
 
4946
 
 
4947
    /**
 
4948
     *  Constructor
 
4949
     */
 
4950
    FileRec()
 
4951
        { init(); type = UNKNOWN; }
 
4952
 
 
4953
    /**
 
4954
     *  Copy constructor
 
4955
     */
 
4956
    FileRec(const FileRec &other)
 
4957
        { init(); assign(other); }
 
4958
    /**
 
4959
     *  Constructor
 
4960
     */
 
4961
    FileRec(int typeVal)
 
4962
        { init(); type = typeVal; }
 
4963
    /**
 
4964
     *  Assignment operator
 
4965
     */
 
4966
    FileRec &operator=(const FileRec &other)
 
4967
        { init(); assign(other); return *this; }
 
4968
 
 
4969
 
 
4970
    /**
 
4971
     *  Destructor
 
4972
     */
 
4973
    ~FileRec()
 
4974
        {}
 
4975
 
 
4976
    /**
 
4977
     *  Directory part of the file name
 
4978
     */
 
4979
    String path;
 
4980
 
 
4981
    /**
 
4982
     *  Base name, sans directory and suffix
 
4983
     */
 
4984
    String baseName;
 
4985
 
 
4986
    /**
 
4987
     *  File extension, such as cpp or h
 
4988
     */
 
4989
    String suffix;
 
4990
 
 
4991
    /**
 
4992
     *  Type of file: CFILE, HFILE, OFILE
 
4993
     */
 
4994
    int type;
 
4995
 
 
4996
    /**
 
4997
     * Used to list files ref'd by this one
 
4998
     */
 
4999
    std::map<String, FileRec *> files;
 
5000
 
 
5001
 
 
5002
private:
 
5003
 
 
5004
    void init()
 
5005
        {
 
5006
        }
 
5007
 
 
5008
    void assign(const FileRec &other)
 
5009
        {
 
5010
        type     = other.type;
 
5011
        baseName = other.baseName;
 
5012
        suffix   = other.suffix;
 
5013
        files    = other.files;
 
5014
        }
 
5015
 
 
5016
};
 
5017
 
 
5018
 
 
5019
 
 
5020
/**
 
5021
 *  Simpler dependency record
 
5022
 */
 
5023
class DepRec
 
5024
{
 
5025
public:
 
5026
 
 
5027
    /**
 
5028
     *  Constructor
 
5029
     */
 
5030
    DepRec()
 
5031
        {init();}
 
5032
 
 
5033
    /**
 
5034
     *  Copy constructor
 
5035
     */
 
5036
    DepRec(const DepRec &other)
 
5037
        {init(); assign(other);}
 
5038
    /**
 
5039
     *  Constructor
 
5040
     */
 
5041
    DepRec(const String &fname)
 
5042
        {init(); name = fname; }
 
5043
    /**
 
5044
     *  Assignment operator
 
5045
     */
 
5046
    DepRec &operator=(const DepRec &other)
 
5047
        {init(); assign(other); return *this;}
 
5048
 
 
5049
 
 
5050
    /**
 
5051
     *  Destructor
 
5052
     */
 
5053
    ~DepRec()
 
5054
        {}
 
5055
 
 
5056
    /**
 
5057
     *  Directory part of the file name
 
5058
     */
 
5059
    String path;
 
5060
 
 
5061
    /**
 
5062
     *  Base name, without the path and suffix
 
5063
     */
 
5064
    String name;
 
5065
 
 
5066
    /**
 
5067
     *  Suffix of the source
 
5068
     */
 
5069
    String suffix;
 
5070
 
 
5071
 
 
5072
    /**
 
5073
     * Used to list files ref'd by this one
 
5074
     */
 
5075
    std::vector<String> files;
 
5076
 
 
5077
 
 
5078
private:
 
5079
 
 
5080
    void init()
 
5081
        {
 
5082
        }
 
5083
 
 
5084
    void assign(const DepRec &other)
 
5085
        {
 
5086
        path     = other.path;
 
5087
        name     = other.name;
 
5088
        suffix   = other.suffix;
 
5089
        files    = other.files; //avoid recursion
 
5090
        }
 
5091
 
 
5092
};
 
5093
 
 
5094
 
 
5095
class DepTool : public MakeBase
 
5096
{
 
5097
public:
 
5098
 
 
5099
    /**
 
5100
     *  Constructor
 
5101
     */
 
5102
    DepTool()
 
5103
        { init(); }
 
5104
 
 
5105
    /**
 
5106
     *  Copy constructor
 
5107
     */
 
5108
    DepTool(const DepTool &other)
 
5109
        { init(); assign(other); }
 
5110
 
 
5111
    /**
 
5112
     *  Assignment operator
 
5113
     */
 
5114
    DepTool &operator=(const DepTool &other)
 
5115
        { init(); assign(other); return *this; }
 
5116
 
 
5117
 
 
5118
    /**
 
5119
     *  Destructor
 
5120
     */
 
5121
    ~DepTool()
 
5122
        {}
 
5123
 
 
5124
 
 
5125
    /**
 
5126
     *  Reset this section of code
 
5127
     */
 
5128
    virtual void init();
 
5129
    
 
5130
    /**
 
5131
     *  Reset this section of code
 
5132
     */
 
5133
    virtual void assign(const DepTool &other)
 
5134
        {
 
5135
        }
 
5136
    
 
5137
    /**
 
5138
     *  Sets the source directory which will be scanned
 
5139
     */
 
5140
    virtual void setSourceDirectory(const String &val)
 
5141
        { sourceDir = val; }
 
5142
 
 
5143
    /**
 
5144
     *  Returns the source directory which will be scanned
 
5145
     */
 
5146
    virtual String getSourceDirectory()
 
5147
        { return sourceDir; }
 
5148
 
 
5149
    /**
 
5150
     *  Sets the list of files within the directory to analyze
 
5151
     */
 
5152
    virtual void setFileList(const std::vector<String> &list)
 
5153
        { fileList = list; }
 
5154
 
 
5155
    /**
 
5156
     * Creates the list of all file names which will be
 
5157
     * candidates for further processing.  Reads make.exclude
 
5158
     * to see which files for directories to leave out.
 
5159
     */
 
5160
    virtual bool createFileList();
 
5161
 
 
5162
 
 
5163
    /**
 
5164
     *  Generates the forward dependency list
 
5165
     */
 
5166
    virtual bool generateDependencies();
 
5167
 
 
5168
 
 
5169
    /**
 
5170
     *  Generates the forward dependency list, saving the file
 
5171
     */
 
5172
    virtual bool generateDependencies(const String &);
 
5173
 
 
5174
 
 
5175
    /**
 
5176
     *  Load a dependency file
 
5177
     */
 
5178
    std::vector<DepRec> loadDepFile(const String &fileName);
 
5179
 
 
5180
    /**
 
5181
     *  Load a dependency file, generating one if necessary
 
5182
     */
 
5183
    std::vector<DepRec> getDepFile(const String &fileName,
 
5184
              bool forceRefresh);
 
5185
 
 
5186
    /**
 
5187
     *  Save a dependency file
 
5188
     */
 
5189
    bool saveDepFile(const String &fileName);
 
5190
 
 
5191
 
 
5192
private:
 
5193
 
 
5194
 
 
5195
    /**
 
5196
     *
 
5197
     */
 
5198
    void parseName(const String &fullname,
 
5199
                   String &path,
 
5200
                   String &basename,
 
5201
                   String &suffix);
 
5202
 
 
5203
    /**
 
5204
     *
 
5205
     */
 
5206
    int get(int pos);
 
5207
 
 
5208
    /**
 
5209
     *
 
5210
     */
 
5211
    int skipwhite(int pos);
 
5212
 
 
5213
    /**
 
5214
     *
 
5215
     */
 
5216
    int getword(int pos, String &ret);
 
5217
 
 
5218
    /**
 
5219
     *
 
5220
     */
 
5221
    bool sequ(int pos, const char *key);
 
5222
 
 
5223
    /**
 
5224
     *
 
5225
     */
 
5226
    bool addIncludeFile(FileRec *frec, const String &fname);
 
5227
 
 
5228
    /**
 
5229
     *
 
5230
     */
 
5231
    bool scanFile(const String &fname, FileRec *frec);
 
5232
 
 
5233
    /**
 
5234
     *
 
5235
     */
 
5236
    bool processDependency(FileRec *ofile, FileRec *include);
 
5237
 
 
5238
    /**
 
5239
     *
 
5240
     */
 
5241
    String sourceDir;
 
5242
 
 
5243
    /**
 
5244
     *
 
5245
     */
 
5246
    std::vector<String> fileList;
 
5247
 
 
5248
    /**
 
5249
     *
 
5250
     */
 
5251
    std::vector<String> directories;
 
5252
 
 
5253
    /**
 
5254
     * A list of all files which will be processed for
 
5255
     * dependencies.
 
5256
     */
 
5257
    std::map<String, FileRec *> allFiles;
 
5258
 
 
5259
    /**
 
5260
     * The list of .o files, and the
 
5261
     * dependencies upon them.
 
5262
     */
 
5263
    std::map<String, FileRec *> oFiles;
 
5264
 
 
5265
    int depFileSize;
 
5266
    char *depFileBuf;
 
5267
 
 
5268
    static const int readBufSize = 8192;
 
5269
    char readBuf[8193];//byte larger
 
5270
 
 
5271
};
 
5272
 
 
5273
 
 
5274
 
 
5275
 
 
5276
 
 
5277
/**
 
5278
 *  Clean up after processing.  Called by the destructor, but should
 
5279
 *  also be called before the object is reused.
 
5280
 */
 
5281
void DepTool::init()
 
5282
{
 
5283
    sourceDir = ".";
 
5284
 
 
5285
    fileList.clear();
 
5286
    directories.clear();
 
5287
    
 
5288
    //clear output file list
 
5289
    std::map<String, FileRec *>::iterator iter;
 
5290
    for (iter=oFiles.begin(); iter!=oFiles.end() ; iter++)
 
5291
        delete iter->second;
 
5292
    oFiles.clear();
 
5293
 
 
5294
    //allFiles actually contains the master copies. delete them
 
5295
    for (iter= allFiles.begin(); iter!=allFiles.end() ; iter++)
 
5296
        delete iter->second;
 
5297
    allFiles.clear(); 
 
5298
 
 
5299
}
 
5300
 
 
5301
 
 
5302
 
 
5303
 
 
5304
/**
 
5305
 *  Parse a full path name into path, base name, and suffix
 
5306
 */
 
5307
void DepTool::parseName(const String &fullname,
 
5308
                        String &path,
 
5309
                        String &basename,
 
5310
                        String &suffix)
 
5311
{
 
5312
    if (fullname.size() < 2)
 
5313
        return;
 
5314
 
 
5315
    unsigned int pos = fullname.find_last_of('/');
 
5316
    if (pos != fullname.npos && pos<fullname.size()-1)
 
5317
        {
 
5318
        path = fullname.substr(0, pos);
 
5319
        pos++;
 
5320
        basename = fullname.substr(pos, fullname.size()-pos);
 
5321
        }
 
5322
    else
 
5323
        {
 
5324
        path = "";
 
5325
        basename = fullname;
 
5326
        }
 
5327
 
 
5328
    pos = basename.find_last_of('.');
 
5329
    if (pos != basename.npos && pos<basename.size()-1)
 
5330
        {
 
5331
        suffix   = basename.substr(pos+1, basename.size()-pos-1);
 
5332
        basename = basename.substr(0, pos);
 
5333
        }
 
5334
 
 
5335
    //trace("parsename:%s %s %s", path.c_str(),
 
5336
    //        basename.c_str(), suffix.c_str()); 
 
5337
}
 
5338
 
 
5339
 
 
5340
 
 
5341
/**
 
5342
 *  Generate our internal file list.
 
5343
 */
 
5344
bool DepTool::createFileList()
 
5345
{
 
5346
 
 
5347
    for (unsigned int i=0 ; i<fileList.size() ; i++)
 
5348
        {
 
5349
        String fileName = fileList[i];
 
5350
        //trace("## FileName:%s", fileName.c_str());
 
5351
        String path;
 
5352
        String basename;
 
5353
        String sfx;
 
5354
        parseName(fileName, path, basename, sfx);
 
5355
        if (sfx == "cpp" || sfx == "c" || sfx == "cxx"   ||
 
5356
            sfx == "cc" || sfx == "CC")
 
5357
            {
 
5358
            FileRec *fe         = new FileRec(FileRec::CFILE);
 
5359
            fe->path            = path;
 
5360
            fe->baseName        = basename;
 
5361
            fe->suffix          = sfx;
 
5362
            allFiles[fileName]  = fe;
 
5363
            }
 
5364
        else if (sfx == "h"   ||  sfx == "hh"  ||
 
5365
                 sfx == "hpp" ||  sfx == "hxx")
 
5366
            {
 
5367
            FileRec *fe         = new FileRec(FileRec::HFILE);
 
5368
            fe->path            = path;
 
5369
            fe->baseName        = basename;
 
5370
            fe->suffix          = sfx;
 
5371
            allFiles[fileName]  = fe;
 
5372
            }
 
5373
        }
 
5374
 
 
5375
    if (!listDirectories(sourceDir, "", directories))
 
5376
        return false;
 
5377
        
 
5378
    return true;
 
5379
}
 
5380
 
 
5381
 
 
5382
 
 
5383
 
 
5384
 
 
5385
/**
 
5386
 * Get a character from the buffer at pos.  If out of range,
 
5387
 * return -1 for safety
 
5388
 */
 
5389
int DepTool::get(int pos)
 
5390
{
 
5391
    if (pos>depFileSize)
 
5392
        return -1;
 
5393
    return depFileBuf[pos];
 
5394
}
 
5395
 
 
5396
 
 
5397
 
 
5398
/**
 
5399
 *  Skip over all whitespace characters beginning at pos.  Return
 
5400
 *  the position of the first non-whitespace character.
 
5401
 */
 
5402
int DepTool::skipwhite(int pos)
 
5403
{
 
5404
    while (pos < depFileSize)
 
5405
        {
 
5406
        int ch = get(pos);
 
5407
        if (ch < 0)
 
5408
            break;
 
5409
        if (!isspace(ch))
 
5410
            break;
 
5411
        pos++;
 
5412
        }
 
5413
    return pos;
 
5414
}
 
5415
 
 
5416
 
 
5417
/**
 
5418
 *  Parse the buffer beginning at pos, for a word.  Fill
 
5419
 *  'ret' with the result.  Return the position after the
 
5420
 *  word.
 
5421
 */
 
5422
int DepTool::getword(int pos, String &ret)
 
5423
{
 
5424
    while (pos < depFileSize)
 
5425
        {
 
5426
        int ch = get(pos);
 
5427
        if (ch < 0)
 
5428
            break;
 
5429
        if (isspace(ch))
 
5430
            break;
 
5431
        ret.push_back((char)ch);
 
5432
        pos++;
 
5433
        }
 
5434
    return pos;
 
5435
}
 
5436
 
 
5437
/**
 
5438
 * Return whether the sequence of characters in the buffer
 
5439
 * beginning at pos match the key,  for the length of the key
 
5440
 */
 
5441
bool DepTool::sequ(int pos, const char *key)
 
5442
{
 
5443
    while (*key)
 
5444
        {
 
5445
        if (*key != get(pos))
 
5446
            return false;
 
5447
        key++; pos++;
 
5448
        }
 
5449
    return true;
 
5450
}
 
5451
 
 
5452
 
 
5453
 
 
5454
/**
 
5455
 *  Add an include file name to a file record.  If the name
 
5456
 *  is not found in allFiles explicitly, try prepending include
 
5457
 *  directory names to it and try again.
 
5458
 */
 
5459
bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
 
5460
{
 
5461
    //# if the name is an exact match to a path name
 
5462
    //# in allFiles, like "myinc.h"
 
5463
    std::map<String, FileRec *>::iterator iter =
 
5464
           allFiles.find(iname);
 
5465
    if (iter != allFiles.end()) //already exists
 
5466
        {
 
5467
         //h file in same dir
 
5468
        FileRec *other = iter->second;
 
5469
        //trace("local: '%s'", iname.c_str());
 
5470
        frec->files[iname] = other;
 
5471
        return true;
 
5472
        }
 
5473
    else 
 
5474
        {
 
5475
        //## Ok, it was not found directly
 
5476
        //look in other dirs
 
5477
        std::vector<String>::iterator diter;
 
5478
        for (diter=directories.begin() ;
 
5479
             diter!=directories.end() ; diter++)
 
5480
            {
 
5481
            String dfname = *diter;
 
5482
            dfname.append("/");
 
5483
            dfname.append(iname);
 
5484
            URI fullPathURI(dfname);  //normalize path name
 
5485
            String fullPath = fullPathURI.getPath();
 
5486
            if (fullPath[0] == '/')
 
5487
                fullPath = fullPath.substr(1);
 
5488
            //trace("Normalized %s to %s", dfname.c_str(), fullPath.c_str());
 
5489
            iter = allFiles.find(fullPath);
 
5490
            if (iter != allFiles.end())
 
5491
                {
 
5492
                FileRec *other = iter->second;
 
5493
                //trace("other: '%s'", iname.c_str());
 
5494
                frec->files[fullPath] = other;
 
5495
                return true;
 
5496
                }
 
5497
            }
 
5498
        }
 
5499
    return true;
 
5500
}
 
5501
 
 
5502
 
 
5503
 
 
5504
/**
 
5505
 *  Lightly parse a file to find the #include directives.  Do
 
5506
 *  a bit of state machine stuff to make sure that the directive
 
5507
 *  is valid.  (Like not in a comment).
 
5508
 */
 
5509
bool DepTool::scanFile(const String &fname, FileRec *frec)
 
5510
{
 
5511
    String fileName;
 
5512
    if (sourceDir.size() > 0)
 
5513
        {
 
5514
        fileName.append(sourceDir);
 
5515
        fileName.append("/");
 
5516
        }
 
5517
    fileName.append(fname);
 
5518
    String nativeName = getNativePath(fileName);
 
5519
    FILE *f = fopen(nativeName.c_str(), "r");
 
5520
    if (!f)
 
5521
        {
 
5522
        error("Could not open '%s' for reading", fname.c_str());
 
5523
        return false;
 
5524
        }
 
5525
    String buf;
 
5526
    while (!feof(f))
 
5527
        {
 
5528
        int len = fread(readBuf, 1, readBufSize, f);
 
5529
        readBuf[len] = '\0';
 
5530
        buf.append(readBuf);
 
5531
        }
 
5532
    fclose(f);
 
5533
 
 
5534
    depFileSize = buf.size();
 
5535
    depFileBuf  = (char *)buf.c_str();
 
5536
    int pos = 0;
 
5537
 
 
5538
 
 
5539
    while (pos < depFileSize)
 
5540
        {
 
5541
        //trace("p:%c", get(pos));
 
5542
 
 
5543
        //# Block comment
 
5544
        if (get(pos) == '/' && get(pos+1) == '*')
 
5545
            {
 
5546
            pos += 2;
 
5547
            while (pos < depFileSize)
 
5548
                {
 
5549
                if (get(pos) == '*' && get(pos+1) == '/')
 
5550
                    {
 
5551
                    pos += 2;
 
5552
                    break;
 
5553
                    }
 
5554
                else
 
5555
                    pos++;
 
5556
                }
 
5557
            }
 
5558
        //# Line comment
 
5559
        else if (get(pos) == '/' && get(pos+1) == '/')
 
5560
            {
 
5561
            pos += 2;
 
5562
            while (pos < depFileSize)
 
5563
                {
 
5564
                if (get(pos) == '\n')
 
5565
                    {
 
5566
                    pos++;
 
5567
                    break;
 
5568
                    }
 
5569
                else
 
5570
                    pos++;
 
5571
                }
 
5572
            }
 
5573
        //# #include! yaay
 
5574
        else if (sequ(pos, "#include"))
 
5575
            {
 
5576
            pos += 8;
 
5577
            pos = skipwhite(pos);
 
5578
            String iname;
 
5579
            pos = getword(pos, iname);
 
5580
            if (iname.size()>2)
 
5581
                {
 
5582
                iname = iname.substr(1, iname.size()-2);
 
5583
                addIncludeFile(frec, iname);
 
5584
                }
 
5585
            }
 
5586
        else
 
5587
            {
 
5588
            pos++;
 
5589
            }
 
5590
        }
 
5591
 
 
5592
    return true;
 
5593
}
 
5594
 
 
5595
 
 
5596
 
 
5597
/**
 
5598
 *  Recursively check include lists to find all files in allFiles to which
 
5599
 *  a given file is dependent.
 
5600
 */
 
5601
bool DepTool::processDependency(FileRec *ofile, FileRec *include)
 
5602
{
 
5603
    std::map<String, FileRec *>::iterator iter;
 
5604
    for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
 
5605
        {
 
5606
        String fname  = iter->first;
 
5607
        if (ofile->files.find(fname) != ofile->files.end())
 
5608
            {
 
5609
            //trace("file '%s' already seen", fname.c_str());
 
5610
            continue;
 
5611
            }
 
5612
        FileRec *child  = iter->second;
 
5613
        ofile->files[fname] = child;
 
5614
      
 
5615
        processDependency(ofile, child);
 
5616
        }
 
5617
 
 
5618
 
 
5619
    return true;
 
5620
}
 
5621
 
 
5622
 
 
5623
 
 
5624
 
 
5625
 
 
5626
/**
 
5627
 *  Generate the file dependency list.
 
5628
 */
 
5629
bool DepTool::generateDependencies()
 
5630
{
 
5631
    std::map<String, FileRec *>::iterator iter;
 
5632
    //# First pass.  Scan for all includes
 
5633
    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
 
5634
        {
 
5635
        FileRec *frec = iter->second;
 
5636
        if (!scanFile(iter->first, frec))
 
5637
            {
 
5638
            //quit?
 
5639
            }
 
5640
        }
 
5641
 
 
5642
    //# Second pass.  Scan for all includes
 
5643
    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
 
5644
        {
 
5645
        FileRec *include = iter->second;
 
5646
        if (include->type == FileRec::CFILE)
 
5647
            {
 
5648
            String cFileName   = iter->first;
 
5649
            FileRec *ofile     = new FileRec(FileRec::OFILE);
 
5650
            ofile->path        = include->path;
 
5651
            ofile->baseName    = include->baseName;
 
5652
            ofile->suffix      = include->suffix;
 
5653
            String fname       = include->path;
 
5654
            if (fname.size()>0)
 
5655
                fname.append("/");
 
5656
            fname.append(include->baseName);
 
5657
            fname.append(".o");
 
5658
            oFiles[fname]    = ofile;
 
5659
            //add the .c file first?   no, don't
 
5660
            //ofile->files[cFileName] = include;
 
5661
            
 
5662
            //trace("ofile:%s", fname.c_str());
 
5663
 
 
5664
            processDependency(ofile, include);
 
5665
            }
 
5666
        }
 
5667
 
 
5668
      
 
5669
    return true;
 
5670
}
 
5671
 
 
5672
 
 
5673
 
 
5674
/**
 
5675
 *  High-level call to generate deps and optionally save them
 
5676
 */
 
5677
bool DepTool::generateDependencies(const String &fileName)
 
5678
{
 
5679
    if (!createFileList())
 
5680
        return false;
 
5681
    if (!generateDependencies())
 
5682
        return false;
 
5683
    if (!saveDepFile(fileName))
 
5684
        return false;
 
5685
    return true;
 
5686
}
 
5687
 
 
5688
 
 
5689
/**
 
5690
 *   This saves the dependency cache.
 
5691
 */
 
5692
bool DepTool::saveDepFile(const String &fileName)
 
5693
{
 
5694
    time_t tim;
 
5695
    time(&tim);
 
5696
 
 
5697
    FILE *f = fopen(fileName.c_str(), "w");
 
5698
    if (!f)
 
5699
        {
 
5700
        trace("cannot open '%s' for writing", fileName.c_str());
 
5701
        }
 
5702
    fprintf(f, "<?xml version='1.0'?>\n");
 
5703
    fprintf(f, "<!--\n");
 
5704
    fprintf(f, "########################################################\n");
 
5705
    fprintf(f, "## File: build.dep\n");
 
5706
    fprintf(f, "## Generated by BuildTool at :%s", ctime(&tim));
 
5707
    fprintf(f, "########################################################\n");
 
5708
    fprintf(f, "-->\n");
 
5709
 
 
5710
    fprintf(f, "<dependencies source='%s'>\n\n", sourceDir.c_str());
 
5711
    std::map<String, FileRec *>::iterator iter;
 
5712
    for (iter=oFiles.begin() ; iter!=oFiles.end() ; iter++)
 
5713
        {
 
5714
        FileRec *frec = iter->second;
 
5715
        if (frec->type == FileRec::OFILE)
 
5716
            {
 
5717
            fprintf(f, "<object path='%s' name='%s' suffix='%s'>\n",
 
5718
                 frec->path.c_str(), frec->baseName.c_str(), frec->suffix.c_str());
 
5719
            std::map<String, FileRec *>::iterator citer;
 
5720
            for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
 
5721
                {
 
5722
                String cfname = citer->first;
 
5723
                fprintf(f, "    <dep name='%s'/>\n", cfname.c_str());
 
5724
                }
 
5725
            fprintf(f, "</object>\n\n");
 
5726
            }
 
5727
        }
 
5728
 
 
5729
    fprintf(f, "</dependencies>\n");
 
5730
    fprintf(f, "\n");
 
5731
    fprintf(f, "<!--\n");
 
5732
    fprintf(f, "########################################################\n");
 
5733
    fprintf(f, "## E N D\n");
 
5734
    fprintf(f, "########################################################\n");
 
5735
    fprintf(f, "-->\n");
 
5736
 
 
5737
    fclose(f);
 
5738
 
 
5739
    return true;
 
5740
}
 
5741
 
 
5742
 
 
5743
 
 
5744
 
 
5745
/**
 
5746
 *   This loads the dependency cache.
 
5747
 */
 
5748
std::vector<DepRec> DepTool::loadDepFile(const String &depFile)
 
5749
{
 
5750
    std::vector<DepRec> result;
 
5751
    
 
5752
    Parser parser;
 
5753
    Element *root = parser.parseFile(depFile.c_str());
 
5754
    if (!root)
 
5755
        {
 
5756
        //error("Could not open %s for reading", depFile.c_str());
 
5757
        return result;
 
5758
        }
 
5759
 
 
5760
    if (root->getChildren().size()==0 ||
 
5761
        root->getChildren()[0]->getName()!="dependencies")
 
5762
        {
 
5763
        error("loadDepFile: main xml element should be <dependencies>");
 
5764
        delete root;
 
5765
        return result;
 
5766
        }
 
5767
 
 
5768
    //########## Start parsing
 
5769
    Element *depList = root->getChildren()[0];
 
5770
 
 
5771
    std::vector<Element *> objects = depList->getChildren();
 
5772
    for (unsigned int i=0 ; i<objects.size() ; i++)
 
5773
        {
 
5774
        Element *objectElem = objects[i];
 
5775
        String tagName = objectElem->getName();
 
5776
        if (tagName != "object")
 
5777
            {
 
5778
            error("loadDepFile: <dependencies> should have only <object> children");
 
5779
            return result;
 
5780
            }
 
5781
 
 
5782
        String objName   = objectElem->getAttribute("name");
 
5783
         //trace("object:%s", objName.c_str());
 
5784
        DepRec depObject(objName);
 
5785
        depObject.path   = objectElem->getAttribute("path");
 
5786
        depObject.suffix = objectElem->getAttribute("suffix");
 
5787
        //########## DESCRIPTION
 
5788
        std::vector<Element *> depElems = objectElem->getChildren();
 
5789
        for (unsigned int i=0 ; i<depElems.size() ; i++)
 
5790
            {
 
5791
            Element *depElem = depElems[i];
 
5792
            tagName = depElem->getName();
 
5793
            if (tagName != "dep")
 
5794
                {
 
5795
                error("loadDepFile: <object> should have only <dep> children");
 
5796
                return result;
 
5797
                }
 
5798
            String depName = depElem->getAttribute("name");
 
5799
            //trace("    dep:%s", depName.c_str());
 
5800
            depObject.files.push_back(depName);
 
5801
            }
 
5802
 
 
5803
        //Insert into the result list, in a sorted manner
 
5804
        bool inserted = false;
 
5805
        std::vector<DepRec>::iterator iter;
 
5806
        for (iter = result.begin() ; iter != result.end() ; iter++)
 
5807
            {
 
5808
            String vpath = iter->path;
 
5809
            vpath.append("/");
 
5810
            vpath.append(iter->name);
 
5811
            String opath = depObject.path;
 
5812
            opath.append("/");
 
5813
            opath.append(depObject.name);
 
5814
            if (vpath > opath)
 
5815
                {
 
5816
                inserted = true;
 
5817
                iter = result.insert(iter, depObject);
 
5818
                break;
 
5819
                }
 
5820
            }
 
5821
        if (!inserted)
 
5822
            result.push_back(depObject);
 
5823
        }
 
5824
 
 
5825
    delete root;
 
5826
 
 
5827
    return result;
 
5828
}
 
5829
 
 
5830
 
 
5831
/**
 
5832
 *   This loads the dependency cache.
 
5833
 */
 
5834
std::vector<DepRec> DepTool::getDepFile(const String &depFile,
 
5835
                   bool forceRefresh)
 
5836
{
 
5837
    std::vector<DepRec> result;
 
5838
    if (forceRefresh)
 
5839
        {
 
5840
        generateDependencies(depFile);
 
5841
        result = loadDepFile(depFile);
 
5842
        }
 
5843
    else
 
5844
        {
 
5845
        //try once
 
5846
        result = loadDepFile(depFile);
 
5847
        if (result.size() == 0)
 
5848
            {
 
5849
            //fail? try again
 
5850
            generateDependencies(depFile);
 
5851
            result = loadDepFile(depFile);
 
5852
            }
 
5853
        }
 
5854
    return result;
 
5855
}
 
5856
 
 
5857
 
 
5858
 
 
5859
 
 
5860
//########################################################################
 
5861
//# T A S K
 
5862
//########################################################################
 
5863
//forward decl
 
5864
class Target;
 
5865
class Make;
 
5866
 
 
5867
/**
 
5868
 *
 
5869
 */
 
5870
class Task : public MakeBase
 
5871
{
 
5872
 
 
5873
public:
 
5874
 
 
5875
    typedef enum
 
5876
        {
 
5877
        TASK_NONE,
 
5878
        TASK_CC,
 
5879
        TASK_COPY,
 
5880
        TASK_DELETE,
 
5881
        TASK_JAR,
 
5882
        TASK_JAVAC,
 
5883
        TASK_LINK,
 
5884
        TASK_MAKEFILE,
 
5885
        TASK_MKDIR,
 
5886
        TASK_MSGFMT,
 
5887
        TASK_PKG_CONFIG,
 
5888
        TASK_RANLIB,
 
5889
        TASK_RC,
 
5890
        TASK_SHAREDLIB,
 
5891
        TASK_STATICLIB,
 
5892
        TASK_STRIP,
 
5893
        TASK_TOUCH,
 
5894
        TASK_TSTAMP
 
5895
        } TaskType;
 
5896
        
 
5897
 
 
5898
    /**
 
5899
     *
 
5900
     */
 
5901
    Task(MakeBase &par) : parent(par)
 
5902
        { init(); }
 
5903
 
 
5904
    /**
 
5905
     *
 
5906
     */
 
5907
    Task(const Task &other) : parent(other.parent)
 
5908
        { init(); assign(other); }
 
5909
 
 
5910
    /**
 
5911
     *
 
5912
     */
 
5913
    Task &operator=(const Task &other)
 
5914
        { assign(other); return *this; }
 
5915
 
 
5916
    /**
 
5917
     *
 
5918
     */
 
5919
    virtual ~Task()
 
5920
        { }
 
5921
 
 
5922
 
 
5923
    /**
 
5924
     *
 
5925
     */
 
5926
    virtual MakeBase &getParent()
 
5927
        { return parent; }
 
5928
 
 
5929
     /**
 
5930
     *
 
5931
     */
 
5932
    virtual int  getType()
 
5933
        { return type; }
 
5934
 
 
5935
    /**
 
5936
     *
 
5937
     */
 
5938
    virtual void setType(int val)
 
5939
        { type = val; }
 
5940
 
 
5941
    /**
 
5942
     *
 
5943
     */
 
5944
    virtual String getName()
 
5945
        { return name; }
 
5946
 
 
5947
    /**
 
5948
     *
 
5949
     */
 
5950
    virtual bool execute()
 
5951
        { return true; }
 
5952
 
 
5953
    /**
 
5954
     *
 
5955
     */
 
5956
    virtual bool parse(Element *elem)
 
5957
        { return true; }
 
5958
 
 
5959
    /**
 
5960
     *
 
5961
     */
 
5962
    Task *createTask(Element *elem, int lineNr);
 
5963
 
 
5964
 
 
5965
protected:
 
5966
 
 
5967
    void init()
 
5968
        {
 
5969
        type = TASK_NONE;
 
5970
        name = "none";
 
5971
        }
 
5972
 
 
5973
    void assign(const Task &other)
 
5974
        {
 
5975
        type = other.type;
 
5976
        name = other.name;
 
5977
        }
 
5978
        
 
5979
    String getAttribute(Element *elem, const String &attrName)
 
5980
        {
 
5981
        String str;
 
5982
        return str;
 
5983
        }
 
5984
 
 
5985
    MakeBase &parent;
 
5986
 
 
5987
    int type;
 
5988
 
 
5989
    String name;
 
5990
};
 
5991
 
 
5992
 
 
5993
 
 
5994
/**
 
5995
 * This task runs the C/C++ compiler.  The compiler is invoked
 
5996
 * for all .c or .cpp files which are newer than their correcsponding
 
5997
 * .o files.  
 
5998
 */
 
5999
class TaskCC : public Task
 
6000
{
 
6001
public:
 
6002
 
 
6003
    TaskCC(MakeBase &par) : Task(par)
 
6004
        {
 
6005
        type = TASK_CC; name = "cc";
 
6006
        ccCommand   = "gcc";
 
6007
        cxxCommand  = "g++";
 
6008
        source      = ".";
 
6009
        dest        = ".";
 
6010
        flags       = "";
 
6011
        defines     = "";
 
6012
        includes    = "";
 
6013
        fileSet.clear();
 
6014
        }
 
6015
 
 
6016
    virtual ~TaskCC()
 
6017
        {}
 
6018
 
 
6019
    virtual bool needsCompiling(const FileRec &depRec,
 
6020
              const String &src, const String &dest)
 
6021
        {
 
6022
        return false;
 
6023
        }
 
6024
 
 
6025
    virtual bool execute()
 
6026
        {
 
6027
        if (!listFiles(parent, fileSet))
 
6028
            return false;
 
6029
            
 
6030
        FILE *f = NULL;
 
6031
        f = fopen("compile.lst", "w");
 
6032
 
 
6033
        bool refreshCache = false;
 
6034
        String fullName = parent.resolve("build.dep");
 
6035
        if (isNewerThan(parent.getURI().getPath(), fullName))
 
6036
            {
 
6037
            status("          : regenerating C/C++ dependency cache");
 
6038
            refreshCache = true;
 
6039
            }
 
6040
 
 
6041
        DepTool depTool;
 
6042
        depTool.setSourceDirectory(source);
 
6043
        depTool.setFileList(fileSet.getFiles());
 
6044
        std::vector<DepRec> deps =
 
6045
             depTool.getDepFile("build.dep", refreshCache);
 
6046
        
 
6047
        String incs;
 
6048
        incs.append("-I");
 
6049
        incs.append(parent.resolve("."));
 
6050
        incs.append(" ");
 
6051
        if (includes.size()>0)
 
6052
            {
 
6053
            incs.append(includes);
 
6054
            incs.append(" ");
 
6055
            }
 
6056
        std::set<String> paths;
 
6057
        std::vector<DepRec>::iterator viter;
 
6058
        for (viter=deps.begin() ; viter!=deps.end() ; viter++)
 
6059
            {
 
6060
            DepRec dep = *viter;
 
6061
            if (dep.path.size()>0)
 
6062
                paths.insert(dep.path);
 
6063
            }
 
6064
        if (source.size()>0)
 
6065
            {
 
6066
            incs.append(" -I");
 
6067
            incs.append(parent.resolve(source));
 
6068
            incs.append(" ");
 
6069
            }
 
6070
        std::set<String>::iterator setIter;
 
6071
        for (setIter=paths.begin() ; setIter!=paths.end() ; setIter++)
 
6072
            {
 
6073
            incs.append(" -I");
 
6074
            String dname;
 
6075
            if (source.size()>0)
 
6076
                {
 
6077
                dname.append(source);
 
6078
                dname.append("/");
 
6079
                }
 
6080
            dname.append(*setIter);
 
6081
            incs.append(parent.resolve(dname));
 
6082
            }
 
6083
        std::vector<String> cfiles;
 
6084
        for (viter=deps.begin() ; viter!=deps.end() ; viter++)
 
6085
            {
 
6086
            DepRec dep = *viter;
 
6087
 
 
6088
            //## Select command
 
6089
            String sfx = dep.suffix;
 
6090
            String command = ccCommand;
 
6091
            if (sfx == "cpp" || sfx == "cxx" || sfx == "c++" ||
 
6092
                 sfx == "cc" || sfx == "CC")
 
6093
                command = cxxCommand;
 
6094
 
 
6095
            //## Make paths
 
6096
            String destPath = dest;
 
6097
            String srcPath  = source;
 
6098
            if (dep.path.size()>0)
 
6099
                {
 
6100
                destPath.append("/");
 
6101
                destPath.append(dep.path);
 
6102
                srcPath.append("/");
 
6103
                srcPath.append(dep.path);
 
6104
                }
 
6105
            //## Make sure destination directory exists
 
6106
            if (!createDirectory(destPath))
 
6107
                return false;
 
6108
                
 
6109
            //## Check whether it needs to be done
 
6110
            String destName;
 
6111
            if (destPath.size()>0)
 
6112
                {
 
6113
                destName.append(destPath);
 
6114
                destName.append("/");
 
6115
                }
 
6116
            destName.append(dep.name);
 
6117
            destName.append(".o");
 
6118
            String destFullName = parent.resolve(destName);
 
6119
            String srcName;
 
6120
            if (srcPath.size()>0)
 
6121
                {
 
6122
                srcName.append(srcPath);
 
6123
                srcName.append("/");
 
6124
                }
 
6125
            srcName.append(dep.name);
 
6126
            srcName.append(".");
 
6127
            srcName.append(dep.suffix);
 
6128
            String srcFullName = parent.resolve(srcName);
 
6129
            bool compileMe = false;
 
6130
            //# First we check if the source is newer than the .o
 
6131
            if (isNewerThan(srcFullName, destFullName))
 
6132
                {
 
6133
                status("          : compile of %s required by %s",
 
6134
                        destFullName.c_str(), srcFullName.c_str());
 
6135
                compileMe = true;
 
6136
                }
 
6137
            else
 
6138
                {
 
6139
                //# secondly, we check if any of the included dependencies
 
6140
                //# of the .c/.cpp is newer than the .o
 
6141
                for (unsigned int i=0 ; i<dep.files.size() ; i++)
 
6142
                    {
 
6143
                    String depName;
 
6144
                    if (source.size()>0)
 
6145
                        {
 
6146
                        depName.append(source);
 
6147
                        depName.append("/");
 
6148
                        }
 
6149
                    depName.append(dep.files[i]);
 
6150
                    String depFullName = parent.resolve(depName);
 
6151
                    bool depRequires = isNewerThan(depFullName, destFullName);
 
6152
                    //trace("%d %s %s\n", depRequires,
 
6153
                    //        destFullName.c_str(), depFullName.c_str());
 
6154
                    if (depRequires)
 
6155
                        {
 
6156
                        status("          : compile of %s required by %s",
 
6157
                                destFullName.c_str(), depFullName.c_str());
 
6158
                        compileMe = true;
 
6159
                        break;
 
6160
                        }
 
6161
                    }
 
6162
                }
 
6163
            if (!compileMe)
 
6164
                {
 
6165
                continue;
 
6166
                }
 
6167
 
 
6168
            //## Assemble the command
 
6169
            String cmd = command;
 
6170
            cmd.append(" -c ");
 
6171
            cmd.append(flags);
 
6172
            cmd.append(" ");
 
6173
            cmd.append(defines);
 
6174
            cmd.append(" ");
 
6175
            cmd.append(incs);
 
6176
            cmd.append(" ");
 
6177
            cmd.append(srcFullName);
 
6178
            cmd.append(" -o ");
 
6179
            cmd.append(destFullName);
 
6180
 
 
6181
            //## Execute the command
 
6182
 
 
6183
            String outString, errString;
 
6184
            bool ret = executeCommand(cmd.c_str(), "", outString, errString);
 
6185
 
 
6186
            if (f)
 
6187
                {
 
6188
                fprintf(f, "########################### File : %s\n",
 
6189
                             srcFullName.c_str());
 
6190
                fprintf(f, "#### COMMAND ###\n");
 
6191
                int col = 0;
 
6192
                for (unsigned int i = 0 ; i < cmd.size() ; i++)
 
6193
                    {
 
6194
                    char ch = cmd[i];
 
6195
                    if (isspace(ch)  && col > 63)
 
6196
                        {
 
6197
                        fputc('\n', f);
 
6198
                        col = 0;
 
6199
                        }
 
6200
                    else
 
6201
                        {
 
6202
                        fputc(ch, f);
 
6203
                        col++;
 
6204
                        }
 
6205
                    if (col > 76)
 
6206
                        {
 
6207
                        fputc('\n', f);
 
6208
                        col = 0;
 
6209
                        }
 
6210
                    }
 
6211
                fprintf(f, "\n");
 
6212
                fprintf(f, "#### STDOUT ###\n%s\n", outString.c_str());
 
6213
                fprintf(f, "#### STDERR ###\n%s\n\n", errString.c_str());
 
6214
                }
 
6215
            if (!ret)
 
6216
                {
 
6217
                error("problem compiling: %s", errString.c_str());
 
6218
                return false;
 
6219
                }
 
6220
                
 
6221
            }
 
6222
 
 
6223
        if (f)
 
6224
            {
 
6225
            fclose(f);
 
6226
            }
 
6227
        
 
6228
        return true;
 
6229
        }
 
6230
 
 
6231
    virtual bool parse(Element *elem)
 
6232
        {
 
6233
        String s;
 
6234
        if (!parent.getAttribute(elem, "command", s))
 
6235
            return false;
 
6236
        if (s.size()>0) { ccCommand = s; cxxCommand = s; }
 
6237
        if (!parent.getAttribute(elem, "cc", s))
 
6238
            return false;
 
6239
        if (s.size()>0) ccCommand = s;
 
6240
        if (!parent.getAttribute(elem, "cxx", s))
 
6241
            return false;
 
6242
        if (s.size()>0) cxxCommand = s;
 
6243
        if (!parent.getAttribute(elem, "destdir", s))
 
6244
            return false;
 
6245
        if (s.size()>0) dest = s;
 
6246
 
 
6247
        std::vector<Element *> children = elem->getChildren();
 
6248
        for (unsigned int i=0 ; i<children.size() ; i++)
 
6249
            {
 
6250
            Element *child = children[i];
 
6251
            String tagName = child->getName();
 
6252
            if (tagName == "flags")
 
6253
                {
 
6254
                if (!parent.getValue(child, flags))
 
6255
                    return false;
 
6256
                flags = strip(flags);
 
6257
                }
 
6258
            else if (tagName == "includes")
 
6259
                {
 
6260
                if (!parent.getValue(child, includes))
 
6261
                    return false;
 
6262
                includes = strip(includes);
 
6263
                }
 
6264
            else if (tagName == "defines")
 
6265
                {
 
6266
                if (!parent.getValue(child, defines))
 
6267
                    return false;
 
6268
                defines = strip(defines);
 
6269
                }
 
6270
            else if (tagName == "fileset")
 
6271
                {
 
6272
                if (!parseFileSet(child, parent, fileSet))
 
6273
                    return false;
 
6274
                source = fileSet.getDirectory();
 
6275
                }
 
6276
            }
 
6277
 
 
6278
        return true;
 
6279
        }
 
6280
        
 
6281
protected:
 
6282
 
 
6283
    String ccCommand;
 
6284
    String cxxCommand;
 
6285
    String source;
 
6286
    String dest;
 
6287
    String flags;
 
6288
    String defines;
 
6289
    String includes;
 
6290
    FileSet fileSet;
 
6291
    
 
6292
};
 
6293
 
 
6294
 
 
6295
 
 
6296
/**
 
6297
 *
 
6298
 */
 
6299
class TaskCopy : public Task
 
6300
{
 
6301
public:
 
6302
 
 
6303
    typedef enum
 
6304
        {
 
6305
        CP_NONE,
 
6306
        CP_TOFILE,
 
6307
        CP_TODIR
 
6308
        } CopyType;
 
6309
 
 
6310
    TaskCopy(MakeBase &par) : Task(par)
 
6311
        {
 
6312
        type = TASK_COPY; name = "copy";
 
6313
        cptype = CP_NONE;
 
6314
        verbose = false;
 
6315
        haveFileSet = false;
 
6316
        }
 
6317
 
 
6318
    virtual ~TaskCopy()
 
6319
        {}
 
6320
 
 
6321
    virtual bool execute()
 
6322
        {
 
6323
        switch (cptype)
 
6324
           {
 
6325
           case CP_TOFILE:
 
6326
               {
 
6327
               if (fileName.size()>0)
 
6328
                   {
 
6329
                   status("          : %s to %s",
 
6330
                        fileName.c_str(), toFileName.c_str());
 
6331
                   String fullSource = parent.resolve(fileName);
 
6332
                   String fullDest = parent.resolve(toFileName);
 
6333
                   //trace("copy %s to file %s", fullSource.c_str(),
 
6334
                   //                       fullDest.c_str());
 
6335
                   if (!isRegularFile(fullSource))
 
6336
                       {
 
6337
                       error("copy : file %s does not exist", fullSource.c_str());
 
6338
                       return false;
 
6339
                       }
 
6340
                   if (!isNewerThan(fullSource, fullDest))
 
6341
                       {
 
6342
                       status("          : skipped");
 
6343
                       return true;
 
6344
                       }
 
6345
                   if (!copyFile(fullSource, fullDest))
 
6346
                       return false;
 
6347
                   status("          : 1 file copied");
 
6348
                   }
 
6349
               return true;
 
6350
               }
 
6351
           case CP_TODIR:
 
6352
               {
 
6353
               if (haveFileSet)
 
6354
                   {
 
6355
                   if (!listFiles(parent, fileSet))
 
6356
                       return false;
 
6357
                   String fileSetDir = fileSet.getDirectory();
 
6358
 
 
6359
                   status("          : %s to %s",
 
6360
                       fileSetDir.c_str(), toDirName.c_str());
 
6361
 
 
6362
                   int nrFiles = 0;
 
6363
                   for (unsigned int i=0 ; i<fileSet.size() ; i++)
 
6364
                       {
 
6365
                       String fileName = fileSet[i];
 
6366
 
 
6367
                       String sourcePath;
 
6368
                       if (fileSetDir.size()>0)
 
6369
                           {
 
6370
                           sourcePath.append(fileSetDir);
 
6371
                           sourcePath.append("/");
 
6372
                           }
 
6373
                       sourcePath.append(fileName);
 
6374
                       String fullSource = parent.resolve(sourcePath);
 
6375
                       
 
6376
                       //Get the immediate parent directory's base name
 
6377
                       String baseFileSetDir = fileSetDir;
 
6378
                       unsigned int pos = baseFileSetDir.find_last_of('/');
 
6379
                       if (pos!=baseFileSetDir.npos &&
 
6380
                                  pos < baseFileSetDir.size()-1)
 
6381
                           baseFileSetDir =
 
6382
                              baseFileSetDir.substr(pos+1,
 
6383
                                   baseFileSetDir.size());
 
6384
                       //Now make the new path
 
6385
                       String destPath;
 
6386
                       if (toDirName.size()>0)
 
6387
                           {
 
6388
                           destPath.append(toDirName);
 
6389
                           destPath.append("/");
 
6390
                           }
 
6391
                       if (baseFileSetDir.size()>0)
 
6392
                           {
 
6393
                           destPath.append(baseFileSetDir);
 
6394
                           destPath.append("/");
 
6395
                           }
 
6396
                       destPath.append(fileName);
 
6397
                       String fullDest = parent.resolve(destPath);
 
6398
                       //trace("fileName:%s", fileName.c_str());
 
6399
                       //trace("copy %s to new dir : %s", fullSource.c_str(),
 
6400
                       //                   fullDest.c_str());
 
6401
                       if (!isNewerThan(fullSource, fullDest))
 
6402
                           {
 
6403
                           //trace("copy skipping %s", fullSource.c_str());
 
6404
                           continue;
 
6405
                           }
 
6406
                       if (!copyFile(fullSource, fullDest))
 
6407
                           return false;
 
6408
                       nrFiles++;
 
6409
                       }
 
6410
                   status("          : %d file(s) copied", nrFiles);
 
6411
                   }
 
6412
               else //file source
 
6413
                   {
 
6414
                   //For file->dir we want only the basename of
 
6415
                   //the source appended to the dest dir
 
6416
                   status("          : %s to %s", 
 
6417
                       fileName.c_str(), toDirName.c_str());
 
6418
                   String baseName = fileName;
 
6419
                   unsigned int pos = baseName.find_last_of('/');
 
6420
                   if (pos!=baseName.npos && pos<baseName.size()-1)
 
6421
                       baseName = baseName.substr(pos+1, baseName.size());
 
6422
                   String fullSource = parent.resolve(fileName);
 
6423
                   String destPath;
 
6424
                   if (toDirName.size()>0)
 
6425
                       {
 
6426
                       destPath.append(toDirName);
 
6427
                       destPath.append("/");
 
6428
                       }
 
6429
                   destPath.append(baseName);
 
6430
                   String fullDest = parent.resolve(destPath);
 
6431
                   //trace("copy %s to new dir : %s", fullSource.c_str(),
 
6432
                   //                       fullDest.c_str());
 
6433
                   if (!isRegularFile(fullSource))
 
6434
                       {
 
6435
                       error("copy : file %s does not exist", fullSource.c_str());
 
6436
                       return false;
 
6437
                       }
 
6438
                   if (!isNewerThan(fullSource, fullDest))
 
6439
                       {
 
6440
                       status("          : skipped");
 
6441
                       return true;
 
6442
                       }
 
6443
                   if (!copyFile(fullSource, fullDest))
 
6444
                       return false;
 
6445
                   status("          : 1 file copied");
 
6446
                   }
 
6447
               return true;
 
6448
               }
 
6449
           }
 
6450
        return true;
 
6451
        }
 
6452
 
 
6453
 
 
6454
    virtual bool parse(Element *elem)
 
6455
        {
 
6456
        if (!parent.getAttribute(elem, "file", fileName))
 
6457
            return false;
 
6458
        if (!parent.getAttribute(elem, "tofile", toFileName))
 
6459
            return false;
 
6460
        if (toFileName.size() > 0)
 
6461
            cptype = CP_TOFILE;
 
6462
        if (!parent.getAttribute(elem, "todir", toDirName))
 
6463
            return false;
 
6464
        if (toDirName.size() > 0)
 
6465
            cptype = CP_TODIR;
 
6466
        String ret;
 
6467
        if (!parent.getAttribute(elem, "verbose", ret))
 
6468
            return false;
 
6469
        if (ret.size()>0 && !getBool(ret, verbose))
 
6470
            return false;
 
6471
            
 
6472
        haveFileSet = false;
 
6473
        
 
6474
        std::vector<Element *> children = elem->getChildren();
 
6475
        for (unsigned int i=0 ; i<children.size() ; i++)
 
6476
            {
 
6477
            Element *child = children[i];
 
6478
            String tagName = child->getName();
 
6479
            if (tagName == "fileset")
 
6480
                {
 
6481
                if (!parseFileSet(child, parent, fileSet))
 
6482
                    {
 
6483
                    error("problem getting fileset");
 
6484
                    return false;
 
6485
                    }
 
6486
                haveFileSet = true;
 
6487
                }
 
6488
            }
 
6489
 
 
6490
        //Perform validity checks
 
6491
        if (fileName.size()>0 && fileSet.size()>0)
 
6492
            {
 
6493
            error("<copy> can only have one of : file= and <fileset>");
 
6494
            return false;
 
6495
            }
 
6496
        if (toFileName.size()>0 && toDirName.size()>0)
 
6497
            {
 
6498
            error("<copy> can only have one of : tofile= or todir=");
 
6499
            return false;
 
6500
            }
 
6501
        if (haveFileSet && toDirName.size()==0)
 
6502
            {
 
6503
            error("a <copy> task with a <fileset> must have : todir=");
 
6504
            return false;
 
6505
            }
 
6506
        if (cptype == CP_TOFILE && fileName.size()==0)
 
6507
            {
 
6508
            error("<copy> tofile= must be associated with : file=");
 
6509
            return false;
 
6510
            }
 
6511
        if (cptype == CP_TODIR && fileName.size()==0 && !haveFileSet)
 
6512
            {
 
6513
            error("<copy> todir= must be associated with : file= or <fileset>");
 
6514
            return false;
 
6515
            }
 
6516
 
 
6517
        return true;
 
6518
        }
 
6519
        
 
6520
private:
 
6521
 
 
6522
    int cptype;
 
6523
    String fileName;
 
6524
    FileSet fileSet;
 
6525
    String toFileName;
 
6526
    String toDirName;
 
6527
    bool verbose;
 
6528
    bool haveFileSet;
 
6529
};
 
6530
 
 
6531
 
 
6532
/**
 
6533
 *
 
6534
 */
 
6535
class TaskDelete : public Task
 
6536
{
 
6537
public:
 
6538
 
 
6539
    typedef enum
 
6540
        {
 
6541
        DEL_FILE,
 
6542
        DEL_DIR,
 
6543
        DEL_FILESET
 
6544
        } DeleteType;
 
6545
 
 
6546
    TaskDelete(MakeBase &par) : Task(par)
 
6547
        { 
 
6548
          type        = TASK_DELETE;
 
6549
          name        = "delete";
 
6550
          delType     = DEL_FILE;
 
6551
          verbose     = false;
 
6552
          quiet       = false;
 
6553
          failOnError = true;
 
6554
        }
 
6555
 
 
6556
    virtual ~TaskDelete()
 
6557
        {}
 
6558
 
 
6559
    virtual bool execute()
 
6560
        {
 
6561
        struct stat finfo;
 
6562
        switch (delType)
 
6563
            {
 
6564
            case DEL_FILE:
 
6565
                {
 
6566
                status("          : %s", fileName.c_str());
 
6567
                String fullName = parent.resolve(fileName);
 
6568
                char *fname = (char *)fullName.c_str();
 
6569
                //does not exist
 
6570
                if (stat(fname, &finfo)<0)
 
6571
                    return true;
 
6572
                //exists but is not a regular file
 
6573
                if (!S_ISREG(finfo.st_mode))
 
6574
                    {
 
6575
                    error("<delete> failed. '%s' exists and is not a regular file",
 
6576
                          fname);
 
6577
                    return false;
 
6578
                    }
 
6579
                if (remove(fname)<0)
 
6580
                    {
 
6581
                    error("<delete> failed: %s", strerror(errno));
 
6582
                    return false;
 
6583
                    }
 
6584
                return true;
 
6585
                }
 
6586
            case DEL_DIR:
 
6587
                {
 
6588
                status("          : %s", dirName.c_str());
 
6589
                String fullDir = parent.resolve(dirName);
 
6590
                if (!removeDirectory(fullDir))
 
6591
                    return false;
 
6592
                return true;
 
6593
                }
 
6594
            }
 
6595
        return true;
 
6596
        }
 
6597
 
 
6598
    virtual bool parse(Element *elem)
 
6599
        {
 
6600
        if (!parent.getAttribute(elem, "file", fileName))
 
6601
            return false;
 
6602
        if (fileName.size() > 0)
 
6603
            delType = DEL_FILE;
 
6604
        if (!parent.getAttribute(elem, "dir", dirName))
 
6605
            return false;
 
6606
        if (dirName.size() > 0)
 
6607
            delType = DEL_DIR;
 
6608
        if (fileName.size()>0 && dirName.size()>0)
 
6609
            {
 
6610
            error("<delete> can have one attribute of file= or dir=");
 
6611
            return false;
 
6612
            }
 
6613
        if (fileName.size()==0 && dirName.size()==0)
 
6614
            {
 
6615
            error("<delete> must have one attribute of file= or dir=");
 
6616
            return false;
 
6617
            }
 
6618
        String ret;
 
6619
        if (!parent.getAttribute(elem, "verbose", ret))
 
6620
            return false;
 
6621
        if (ret.size()>0 && !getBool(ret, verbose))
 
6622
            return false;
 
6623
        if (!parent.getAttribute(elem, "quiet", ret))
 
6624
            return false;
 
6625
        if (ret.size()>0 && !getBool(ret, quiet))
 
6626
            return false;
 
6627
        if (!parent.getAttribute(elem, "failonerror", ret))
 
6628
            return false;
 
6629
        if (ret.size()>0 && !getBool(ret, failOnError))
 
6630
            return false;
 
6631
        return true;
 
6632
        }
 
6633
 
 
6634
private:
 
6635
 
 
6636
    int delType;
 
6637
    String dirName;
 
6638
    String fileName;
 
6639
    bool verbose;
 
6640
    bool quiet;
 
6641
    bool failOnError;
 
6642
};
 
6643
 
 
6644
 
 
6645
/**
 
6646
 *
 
6647
 */
 
6648
class TaskJar : public Task
 
6649
{
 
6650
public:
 
6651
 
 
6652
    TaskJar(MakeBase &par) : Task(par)
 
6653
        { type = TASK_JAR; name = "jar"; }
 
6654
 
 
6655
    virtual ~TaskJar()
 
6656
        {}
 
6657
 
 
6658
    virtual bool execute()
 
6659
        {
 
6660
        return true;
 
6661
        }
 
6662
 
 
6663
    virtual bool parse(Element *elem)
 
6664
        {
 
6665
        return true;
 
6666
        }
 
6667
};
 
6668
 
 
6669
 
 
6670
/**
 
6671
 *
 
6672
 */
 
6673
class TaskJavac : public Task
 
6674
{
 
6675
public:
 
6676
 
 
6677
    TaskJavac(MakeBase &par) : Task(par)
 
6678
        { 
 
6679
        type = TASK_JAVAC; name = "javac";
 
6680
        command = "javac";
 
6681
        }
 
6682
 
 
6683
    virtual ~TaskJavac()
 
6684
        {}
 
6685
 
 
6686
    virtual bool execute()
 
6687
        {
 
6688
        std::vector<String> fileList;
 
6689
        if (!listFiles(srcdir, "", fileList))
 
6690
            {
 
6691
            return false;
 
6692
            }
 
6693
        String cmd = command;
 
6694
        cmd.append(" -d ");
 
6695
        cmd.append(destdir);
 
6696
        cmd.append(" -sourcepath ");
 
6697
        cmd.append(srcdir);
 
6698
        cmd.append(" ");
 
6699
        for (unsigned int i=0 ; i<fileList.size() ; i++)
 
6700
            {
 
6701
            String fname = fileList[i];
 
6702
            String srcName = fname;
 
6703
            if (fname.size()<6) //x.java
 
6704
                continue;
 
6705
            if (fname.compare(fname.size()-5, 5, ".java") != 0)
 
6706
                continue;
 
6707
            String baseName = fname.substr(0, fname.size()-5);
 
6708
            String destName = baseName;
 
6709
            destName.append(".class");
 
6710
 
 
6711
            String fullSrc = srcdir;
 
6712
            fullSrc.append("/");
 
6713
            fullSrc.append(fname);
 
6714
            String fullDest = destdir;
 
6715
            fullDest.append("/");
 
6716
            fullDest.append(destName);
 
6717
            //trace("fullsrc:%s fulldest:%s", fullSrc.c_str(), fullDest.c_str());
 
6718
            if (!isNewerThan(fullSrc, fullDest))
 
6719
                continue;
 
6720
 
 
6721
            String execCmd = cmd;
 
6722
            execCmd.append(fullSrc);
 
6723
 
 
6724
            String outString, errString;
 
6725
            bool ret = executeCommand(execCmd.c_str(), "", outString, errString);
 
6726
            if (!ret)
 
6727
                {
 
6728
                error("<javac> command '%s' failed :\n %s",
 
6729
                                          execCmd.c_str(), errString.c_str());
 
6730
                return false;
 
6731
                }
 
6732
            }
 
6733
        return true;
 
6734
        }
 
6735
 
 
6736
    virtual bool parse(Element *elem)
 
6737
        {
 
6738
        String s;
 
6739
        if (!parent.getAttribute(elem, "command", s))
 
6740
            return false;
 
6741
        if (s.size() > 0)
 
6742
            command = s;
 
6743
        if (!parent.getAttribute(elem, "srcdir", srcdir))
 
6744
            return false;
 
6745
        if (!parent.getAttribute(elem, "destdir", destdir))
 
6746
            return false;
 
6747
        if (srcdir.size() == 0 || destdir.size() == 0)
 
6748
            {
 
6749
            error("<javac> required both srcdir and destdir attributes to be set");
 
6750
            return false;
 
6751
            }
 
6752
        return true;
 
6753
        }
 
6754
 
 
6755
private:
 
6756
 
 
6757
    String command;
 
6758
    String srcdir;
 
6759
    String destdir;
 
6760
 
 
6761
};
 
6762
 
 
6763
 
 
6764
/**
 
6765
 *
 
6766
 */
 
6767
class TaskLink : public Task
 
6768
{
 
6769
public:
 
6770
 
 
6771
    TaskLink(MakeBase &par) : Task(par)
 
6772
        {
 
6773
        type = TASK_LINK; name = "link";
 
6774
        command = "g++";
 
6775
        doStrip = false;
 
6776
        stripCommand = "strip";
 
6777
        objcopyCommand = "objcopy";
 
6778
        }
 
6779
 
 
6780
    virtual ~TaskLink()
 
6781
        {}
 
6782
 
 
6783
    virtual bool execute()
 
6784
        {
 
6785
        if (!listFiles(parent, fileSet))
 
6786
            return false;
 
6787
        String fileSetDir = fileSet.getDirectory();
 
6788
        //trace("%d files in %s", fileSet.size(), fileSetDir.c_str());
 
6789
        bool doit = false;
 
6790
        String fullTarget = parent.resolve(fileName);
 
6791
        String cmd = command;
 
6792
        cmd.append(" -o ");
 
6793
        cmd.append(fullTarget);
 
6794
        cmd.append(" ");
 
6795
        cmd.append(flags);
 
6796
        for (unsigned int i=0 ; i<fileSet.size() ; i++)
 
6797
            {
 
6798
            cmd.append(" ");
 
6799
            String obj;
 
6800
            if (fileSetDir.size()>0)
 
6801
                {
 
6802
                obj.append(fileSetDir);
 
6803
                obj.append("/");
 
6804
                }
 
6805
            obj.append(fileSet[i]);
 
6806
            String fullObj = parent.resolve(obj);
 
6807
            String nativeFullObj = getNativePath(fullObj);
 
6808
            cmd.append(nativeFullObj);
 
6809
            //trace("link: tgt:%s obj:%s", fullTarget.c_str(),
 
6810
            //          fullObj.c_str());
 
6811
            if (isNewerThan(fullObj, fullTarget))
 
6812
                doit = true;
 
6813
            }
 
6814
        cmd.append(" ");
 
6815
        cmd.append(libs);
 
6816
        if (!doit)
 
6817
            {
 
6818
            //trace("link not needed");
 
6819
            return true;
 
6820
            }
 
6821
        //trace("LINK cmd:%s", cmd.c_str());
 
6822
 
 
6823
 
 
6824
        String outbuf, errbuf;
 
6825
        if (!executeCommand(cmd.c_str(), "", outbuf, errbuf))
 
6826
            {
 
6827
            error("LINK problem: %s", errbuf.c_str());
 
6828
            return false;
 
6829
            }
 
6830
 
 
6831
        if (symFileName.size()>0)
 
6832
            {
 
6833
            String symFullName = parent.resolve(symFileName);
 
6834
            cmd = objcopyCommand;
 
6835
            cmd.append(" --only-keep-debug ");
 
6836
            cmd.append(getNativePath(fullTarget));
 
6837
            cmd.append(" ");
 
6838
            cmd.append(getNativePath(symFullName));
 
6839
            if (!executeCommand(cmd, "", outbuf, errbuf))
 
6840
                {
 
6841
                error("<strip> symbol file failed : %s", errbuf.c_str());
 
6842
                return false;
 
6843
                }
 
6844
            }
 
6845
            
 
6846
        if (doStrip)
 
6847
            {
 
6848
            cmd = stripCommand;
 
6849
            cmd.append(" ");
 
6850
            cmd.append(getNativePath(fullTarget));
 
6851
            if (!executeCommand(cmd, "", outbuf, errbuf))
 
6852
               {
 
6853
               error("<strip> failed : %s", errbuf.c_str());
 
6854
               return false;
 
6855
               }
 
6856
            }
 
6857
 
 
6858
        return true;
 
6859
        }
 
6860
 
 
6861
    virtual bool parse(Element *elem)
 
6862
        {
 
6863
        String s;
 
6864
        if (!parent.getAttribute(elem, "command", s))
 
6865
            return false;
 
6866
        if (s.size()>0)
 
6867
            command = s;
 
6868
        if (!parent.getAttribute(elem, "objcopycommand", s))
 
6869
            return false;
 
6870
        if (s.size()>0)
 
6871
            objcopyCommand = s;
 
6872
        if (!parent.getAttribute(elem, "stripcommand", s))
 
6873
            return false;
 
6874
        if (s.size()>0)
 
6875
            stripCommand = s;
 
6876
        if (!parent.getAttribute(elem, "out", fileName))
 
6877
            return false;
 
6878
        if (!parent.getAttribute(elem, "strip", s))
 
6879
            return false;
 
6880
        if (s.size()>0 && !getBool(s, doStrip))
 
6881
            return false;
 
6882
        if (!parent.getAttribute(elem, "symfile", symFileName))
 
6883
            return false;
 
6884
            
 
6885
        std::vector<Element *> children = elem->getChildren();
 
6886
        for (unsigned int i=0 ; i<children.size() ; i++)
 
6887
            {
 
6888
            Element *child = children[i];
 
6889
            String tagName = child->getName();
 
6890
            if (tagName == "fileset")
 
6891
                {
 
6892
                if (!parseFileSet(child, parent, fileSet))
 
6893
                    return false;
 
6894
                }
 
6895
            else if (tagName == "flags")
 
6896
                {
 
6897
                if (!parent.getValue(child, flags))
 
6898
                    return false;
 
6899
                flags = strip(flags);
 
6900
                }
 
6901
            else if (tagName == "libs")
 
6902
                {
 
6903
                if (!parent.getValue(child, libs))
 
6904
                    return false;
 
6905
                libs = strip(libs);
 
6906
                }
 
6907
            }
 
6908
        return true;
 
6909
        }
 
6910
 
 
6911
private:
 
6912
 
 
6913
    String  command;
 
6914
    String  fileName;
 
6915
    String  flags;
 
6916
    String  libs;
 
6917
    FileSet fileSet;
 
6918
    bool    doStrip;
 
6919
    String  symFileName;
 
6920
    String  stripCommand;
 
6921
    String  objcopyCommand;
 
6922
 
 
6923
};
 
6924
 
 
6925
 
 
6926
 
 
6927
/**
 
6928
 * Create a named directory
 
6929
 */
 
6930
class TaskMakeFile : public Task
 
6931
{
 
6932
public:
 
6933
 
 
6934
    TaskMakeFile(MakeBase &par) : Task(par)
 
6935
        { type = TASK_MAKEFILE; name = "makefile"; }
 
6936
 
 
6937
    virtual ~TaskMakeFile()
 
6938
        {}
 
6939
 
 
6940
    virtual bool execute()
 
6941
        {
 
6942
        status("          : %s", fileName.c_str());
 
6943
        String fullName = parent.resolve(fileName);
 
6944
        if (!isNewerThan(parent.getURI().getPath(), fullName))
 
6945
            {
 
6946
            //trace("skipped <makefile>");
 
6947
            return true;
 
6948
            }
 
6949
        String fullNative = getNativePath(fullName);
 
6950
        //trace("fullName:%s", fullName.c_str());
 
6951
        FILE *f = fopen(fullNative.c_str(), "w");
 
6952
        if (!f)
 
6953
            {
 
6954
            error("<makefile> could not open %s for writing : %s",
 
6955
                fullName.c_str(), strerror(errno));
 
6956
            return false;
 
6957
            }
 
6958
        for (unsigned int i=0 ; i<text.size() ; i++)
 
6959
            fputc(text[i], f);
 
6960
        fputc('\n', f);
 
6961
        fclose(f);
 
6962
        return true;
 
6963
        }
 
6964
 
 
6965
    virtual bool parse(Element *elem)
 
6966
        {
 
6967
        if (!parent.getAttribute(elem, "file", fileName))
 
6968
            return false;
 
6969
        if (fileName.size() == 0)
 
6970
            {
 
6971
            error("<makefile> requires 'file=\"filename\"' attribute");
 
6972
            return false;
 
6973
            }
 
6974
        if (!parent.getValue(elem, text))
 
6975
            return false;
 
6976
        text = leftJustify(text);
 
6977
        //trace("dirname:%s", dirName.c_str());
 
6978
        return true;
 
6979
        }
 
6980
 
 
6981
private:
 
6982
 
 
6983
    String fileName;
 
6984
    String text;
 
6985
};
 
6986
 
 
6987
 
 
6988
 
 
6989
/**
 
6990
 * Create a named directory
 
6991
 */
 
6992
class TaskMkDir : public Task
 
6993
{
 
6994
public:
 
6995
 
 
6996
    TaskMkDir(MakeBase &par) : Task(par)
 
6997
        { type = TASK_MKDIR; name = "mkdir"; }
 
6998
 
 
6999
    virtual ~TaskMkDir()
 
7000
        {}
 
7001
 
 
7002
    virtual bool execute()
 
7003
        {
 
7004
        status("          : %s", dirName.c_str());
 
7005
        String fullDir = parent.resolve(dirName);
 
7006
        //trace("fullDir:%s", fullDir.c_str());
 
7007
        if (!createDirectory(fullDir))
 
7008
            return false;
 
7009
        return true;
 
7010
        }
 
7011
 
 
7012
    virtual bool parse(Element *elem)
 
7013
        {
 
7014
        if (!parent.getAttribute(elem, "dir", dirName))
 
7015
            return false;
 
7016
        if (dirName.size() == 0)
 
7017
            {
 
7018
            error("<mkdir> requires 'dir=\"dirname\"' attribute");
 
7019
            return false;
 
7020
            }
 
7021
        return true;
 
7022
        }
 
7023
 
 
7024
private:
 
7025
 
 
7026
    String dirName;
 
7027
};
 
7028
 
 
7029
 
 
7030
 
 
7031
/**
 
7032
 * Create a named directory
 
7033
 */
 
7034
class TaskMsgFmt: public Task
 
7035
{
 
7036
public:
 
7037
 
 
7038
    TaskMsgFmt(MakeBase &par) : Task(par)
 
7039
         {
 
7040
         type    = TASK_MSGFMT;
 
7041
         name    = "msgfmt";
 
7042
         command = "msgfmt";
 
7043
         owndir  = false;
 
7044
         outName = "";
 
7045
         }
 
7046
 
 
7047
    virtual ~TaskMsgFmt()
 
7048
        {}
 
7049
 
 
7050
    virtual bool execute()
 
7051
        {
 
7052
        if (!listFiles(parent, fileSet))
 
7053
            return false;
 
7054
        String fileSetDir = fileSet.getDirectory();
 
7055
 
 
7056
        //trace("msgfmt: %d", fileSet.size());
 
7057
        for (unsigned int i=0 ; i<fileSet.size() ; i++)
 
7058
            {
 
7059
            String fileName = fileSet[i];
 
7060
            if (getSuffix(fileName) != "po")
 
7061
                continue;
 
7062
            String sourcePath;
 
7063
            if (fileSetDir.size()>0)
 
7064
                {
 
7065
                sourcePath.append(fileSetDir);
 
7066
                sourcePath.append("/");
 
7067
                }
 
7068
            sourcePath.append(fileName);
 
7069
            String fullSource = parent.resolve(sourcePath);
 
7070
 
 
7071
            String destPath;
 
7072
            if (toDirName.size()>0)
 
7073
                {
 
7074
                destPath.append(toDirName);
 
7075
                destPath.append("/");
 
7076
                }
 
7077
            if (owndir)
 
7078
                {
 
7079
                String subdir = fileName;
 
7080
                unsigned int pos = subdir.find_last_of('.');
 
7081
                if (pos != subdir.npos)
 
7082
                    subdir = subdir.substr(0, pos);
 
7083
                destPath.append(subdir);
 
7084
                destPath.append("/");
 
7085
                }
 
7086
            //Pick the output file name
 
7087
            if (outName.size() > 0)
 
7088
                {
 
7089
                destPath.append(outName);
 
7090
                }
 
7091
            else
 
7092
                {
 
7093
                destPath.append(fileName);
 
7094
                destPath[destPath.size()-2] = 'm';
 
7095
                }
 
7096
 
 
7097
            String fullDest = parent.resolve(destPath);
 
7098
 
 
7099
            if (!isNewerThan(fullSource, fullDest))
 
7100
                {
 
7101
                //trace("skip %s", fullSource.c_str());
 
7102
                continue;
 
7103
                }
 
7104
                
 
7105
            String cmd = command;
 
7106
            cmd.append(" ");
 
7107
            cmd.append(fullSource);
 
7108
            cmd.append(" -o ");
 
7109
            cmd.append(fullDest);
 
7110
            
 
7111
            int pos = fullDest.find_last_of('/');
 
7112
            if (pos>0)
 
7113
                {
 
7114
                String fullDestPath = fullDest.substr(0, pos);
 
7115
                if (!createDirectory(fullDestPath))
 
7116
                    return false;
 
7117
                }
 
7118
 
 
7119
 
 
7120
 
 
7121
            String outString, errString;
 
7122
            if (!executeCommand(cmd.c_str(), "", outString, errString))
 
7123
                {
 
7124
                error("<msgfmt> problem: %s", errString.c_str());
 
7125
                return false;
 
7126
                }
 
7127
            }
 
7128
 
 
7129
        return true;
 
7130
        }
 
7131
 
 
7132
    virtual bool parse(Element *elem)
 
7133
        {
 
7134
        String s;
 
7135
        if (!parent.getAttribute(elem, "command", s))
 
7136
            return false;
 
7137
        if (s.size()>0)
 
7138
            command = s;
 
7139
        if (!parent.getAttribute(elem, "todir", toDirName))
 
7140
            return false;
 
7141
        if (!parent.getAttribute(elem, "out", outName))
 
7142
            return false;
 
7143
        if (!parent.getAttribute(elem, "owndir", s))
 
7144
            return false;
 
7145
        if (s.size()>0 && !getBool(s, owndir))
 
7146
            return false;
 
7147
            
 
7148
        std::vector<Element *> children = elem->getChildren();
 
7149
        for (unsigned int i=0 ; i<children.size() ; i++)
 
7150
            {
 
7151
            Element *child = children[i];
 
7152
            String tagName = child->getName();
 
7153
            if (tagName == "fileset")
 
7154
                {
 
7155
                if (!parseFileSet(child, parent, fileSet))
 
7156
                    return false;
 
7157
                }
 
7158
            }
 
7159
        return true;
 
7160
        }
 
7161
 
 
7162
private:
 
7163
 
 
7164
    String  command;
 
7165
    String  toDirName;
 
7166
    String  outName;
 
7167
    FileSet fileSet;
 
7168
    bool    owndir;
 
7169
 
 
7170
};
 
7171
 
 
7172
 
 
7173
 
 
7174
/**
 
7175
 *  Perform a Package-Config query similar to pkg-config
 
7176
 */
 
7177
class TaskPkgConfig : public Task
 
7178
{
 
7179
public:
 
7180
 
 
7181
    typedef enum
 
7182
        {
 
7183
        PKG_CONFIG_QUERY_CFLAGS,
 
7184
        PKG_CONFIG_QUERY_LIBS,
 
7185
        PKG_CONFIG_QUERY_ALL
 
7186
        } QueryTypes;
 
7187
 
 
7188
    TaskPkgConfig(MakeBase &par) : Task(par)
 
7189
        {
 
7190
        type = TASK_PKG_CONFIG;
 
7191
        name = "pkg-config";
 
7192
        }
 
7193
 
 
7194
    virtual ~TaskPkgConfig()
 
7195
        {}
 
7196
 
 
7197
    virtual bool execute()
 
7198
        {
 
7199
        String path = parent.resolve(pkg_config_path);
 
7200
        PkgConfig pkgconfig;
 
7201
        pkgconfig.setPath(path);
 
7202
        pkgconfig.setPrefix(prefix);
 
7203
        if (!pkgconfig.query(pkgName))
 
7204
            {
 
7205
            error("<pkg-config> query failed for '%s", name.c_str());
 
7206
            return false;
 
7207
            }
 
7208
        String ret;
 
7209
        switch (query)
 
7210
            {
 
7211
            case PKG_CONFIG_QUERY_CFLAGS:
 
7212
                {
 
7213
                ret = pkgconfig.getCflags();
 
7214
                break;
 
7215
                }
 
7216
            case PKG_CONFIG_QUERY_LIBS:
 
7217
                {
 
7218
                ret = pkgconfig.getLibs();
 
7219
                break;
 
7220
                }
 
7221
            case PKG_CONFIG_QUERY_ALL:
 
7222
                {
 
7223
                ret = pkgconfig.getAll();
 
7224
                break;
 
7225
                }
 
7226
            default:
 
7227
                {
 
7228
                error("<pkg-config> unhandled query : %d", query);
 
7229
                return false;
 
7230
                }
 
7231
            
 
7232
            }
 
7233
        status("          : %s", ret.c_str());
 
7234
        parent.setProperty(propName, ret);
 
7235
        return true;
 
7236
        }
 
7237
 
 
7238
    virtual bool parse(Element *elem)
 
7239
        {
 
7240
        String s;
 
7241
        //# NAME
 
7242
        if (!parent.getAttribute(elem, "name", s))
 
7243
            return false;
 
7244
        if (s.size()>0)
 
7245
           pkgName = s;
 
7246
        else
 
7247
            {
 
7248
            error("<pkg-config> requires 'name=\"package\"' attribute");
 
7249
            return false;
 
7250
            }
 
7251
 
 
7252
        //# PROPERTY
 
7253
        if (!parent.getAttribute(elem, "property", s))
 
7254
            return false;
 
7255
        if (s.size()>0)
 
7256
           propName = s;
 
7257
        else
 
7258
            {
 
7259
            error("<pkg-config> requires 'property=\"name\"' attribute");
 
7260
            return false;
 
7261
            }
 
7262
        if (parent.hasProperty(propName))
 
7263
            {
 
7264
            error("<pkg-config> property '%s' is already defined",
 
7265
                          propName.c_str());
 
7266
            return false;
 
7267
            }
 
7268
        parent.setProperty(propName, "undefined");
 
7269
 
 
7270
        //# PATH
 
7271
        if (!parent.getAttribute(elem, "path", s))
 
7272
            return false;
 
7273
        if (s.size()>0)
 
7274
           pkg_config_path = s;
 
7275
 
 
7276
        //# PREFIX
 
7277
        if (!parent.getAttribute(elem, "prefix", s))
 
7278
            return false;
 
7279
        if (s.size()>0)
 
7280
           prefix = s;
 
7281
 
 
7282
        //# QUERY
 
7283
        if (!parent.getAttribute(elem, "query", s))
 
7284
            return false;
 
7285
        if (s == "cflags")
 
7286
            query = PKG_CONFIG_QUERY_CFLAGS;
 
7287
        else if (s == "libs")
 
7288
            query = PKG_CONFIG_QUERY_LIBS;
 
7289
        else if (s == "both")
 
7290
            query = PKG_CONFIG_QUERY_ALL;
 
7291
        else
 
7292
            {
 
7293
            error("<pkg-config> requires 'query=\"type\"' attribute");
 
7294
            error("where type = cflags, libs, or both");
 
7295
            return false;
 
7296
            }
 
7297
        return true;
 
7298
        }
 
7299
 
 
7300
private:
 
7301
 
 
7302
    String pkgName;
 
7303
    String prefix;
 
7304
    String propName;
 
7305
    String pkg_config_path;
 
7306
    int query;
 
7307
 
 
7308
};
 
7309
 
 
7310
 
 
7311
 
 
7312
 
 
7313
 
 
7314
 
 
7315
/**
 
7316
 *  Process an archive to allow random access
 
7317
 */
 
7318
class TaskRanlib : public Task
 
7319
{
 
7320
public:
 
7321
 
 
7322
    TaskRanlib(MakeBase &par) : Task(par)
 
7323
        {
 
7324
        type = TASK_RANLIB; name = "ranlib";
 
7325
        command = "ranlib";
 
7326
        }
 
7327
 
 
7328
    virtual ~TaskRanlib()
 
7329
        {}
 
7330
 
 
7331
    virtual bool execute()
 
7332
        {
 
7333
        String fullName = parent.resolve(fileName);
 
7334
        //trace("fullDir:%s", fullDir.c_str());
 
7335
        String cmd = command;
 
7336
        cmd.append(" ");
 
7337
        cmd.append(fullName);
 
7338
        String outbuf, errbuf;
 
7339
        if (!executeCommand(cmd, "", outbuf, errbuf))
 
7340
            return false;
 
7341
        return true;
 
7342
        }
 
7343
 
 
7344
    virtual bool parse(Element *elem)
 
7345
        {
 
7346
        String s;
 
7347
        if (!parent.getAttribute(elem, "command", s))
 
7348
            return false;
 
7349
        if (s.size()>0)
 
7350
           command = s;
 
7351
        if (!parent.getAttribute(elem, "file", fileName))
 
7352
            return false;
 
7353
        if (fileName.size() == 0)
 
7354
            {
 
7355
            error("<ranlib> requires 'file=\"fileNname\"' attribute");
 
7356
            return false;
 
7357
            }
 
7358
        return true;
 
7359
        }
 
7360
 
 
7361
private:
 
7362
 
 
7363
    String fileName;
 
7364
    String command;
 
7365
};
 
7366
 
 
7367
 
 
7368
 
 
7369
/**
 
7370
 * Run the "ar" command to archive .o's into a .a
 
7371
 */
 
7372
class TaskRC : public Task
 
7373
{
 
7374
public:
 
7375
 
 
7376
    TaskRC(MakeBase &par) : Task(par)
 
7377
        {
 
7378
        type = TASK_RC; name = "rc";
 
7379
        command = "windres";
 
7380
        }
 
7381
 
 
7382
    virtual ~TaskRC()
 
7383
        {}
 
7384
 
 
7385
    virtual bool execute()
 
7386
        {
 
7387
        String fullFile = parent.resolve(fileName);
 
7388
        String fullOut  = parent.resolve(outName);
 
7389
        if (!isNewerThan(fullFile, fullOut))
 
7390
            return true;
 
7391
        String cmd = command;
 
7392
        cmd.append(" -o ");
 
7393
        cmd.append(fullOut);
 
7394
        cmd.append(" ");
 
7395
        cmd.append(flags);
 
7396
        cmd.append(" ");
 
7397
        cmd.append(fullFile);
 
7398
 
 
7399
        String outString, errString;
 
7400
        if (!executeCommand(cmd.c_str(), "", outString, errString))
 
7401
            {
 
7402
            error("RC problem: %s", errString.c_str());
 
7403
            return false;
 
7404
            }
 
7405
        return true;
 
7406
        }
 
7407
 
 
7408
    virtual bool parse(Element *elem)
 
7409
        {
 
7410
        if (!parent.getAttribute(elem, "command", command))
 
7411
            return false;
 
7412
        if (!parent.getAttribute(elem, "file", fileName))
 
7413
            return false;
 
7414
        if (!parent.getAttribute(elem, "out", outName))
 
7415
            return false;
 
7416
        std::vector<Element *> children = elem->getChildren();
 
7417
        for (unsigned int i=0 ; i<children.size() ; i++)
 
7418
            {
 
7419
            Element *child = children[i];
 
7420
            String tagName = child->getName();
 
7421
            if (tagName == "flags")
 
7422
                {
 
7423
                if (!parent.getValue(child, flags))
 
7424
                    return false;
 
7425
                }
 
7426
            }
 
7427
        return true;
 
7428
        }
 
7429
 
 
7430
private:
 
7431
 
 
7432
    String command;
 
7433
    String flags;
 
7434
    String fileName;
 
7435
    String outName;
 
7436
 
 
7437
};
 
7438
 
 
7439
 
 
7440
 
 
7441
/**
 
7442
 *  Collect .o's into a .so or DLL
 
7443
 */
 
7444
class TaskSharedLib : public Task
 
7445
{
 
7446
public:
 
7447
 
 
7448
    TaskSharedLib(MakeBase &par) : Task(par)
 
7449
        {
 
7450
        type = TASK_SHAREDLIB; name = "dll";
 
7451
        command = "dllwrap";
 
7452
        }
 
7453
 
 
7454
    virtual ~TaskSharedLib()
 
7455
        {}
 
7456
 
 
7457
    virtual bool execute()
 
7458
        {
 
7459
        //trace("###########HERE %d", fileSet.size());
 
7460
        bool doit = false;
 
7461
        
 
7462
        String fullOut = parent.resolve(fileName);
 
7463
        //trace("ar fullout: %s", fullOut.c_str());
 
7464
        
 
7465
        if (!listFiles(parent, fileSet))
 
7466
            return false;
 
7467
        String fileSetDir = fileSet.getDirectory();
 
7468
 
 
7469
        for (unsigned int i=0 ; i<fileSet.size() ; i++)
 
7470
            {
 
7471
            String fname;
 
7472
            if (fileSetDir.size()>0)
 
7473
                {
 
7474
                fname.append(fileSetDir);
 
7475
                fname.append("/");
 
7476
                }
 
7477
            fname.append(fileSet[i]);
 
7478
            String fullName = parent.resolve(fname);
 
7479
            //trace("ar : %s/%s", fullOut.c_str(), fullName.c_str());
 
7480
            if (isNewerThan(fullName, fullOut))
 
7481
                doit = true;
 
7482
            }
 
7483
        //trace("Needs it:%d", doit);
 
7484
        if (!doit)
 
7485
            {
 
7486
            return true;
 
7487
            }
 
7488
 
 
7489
        String cmd = "dllwrap";
 
7490
        cmd.append(" -o ");
 
7491
        cmd.append(fullOut);
 
7492
        if (defFileName.size()>0)
 
7493
            {
 
7494
            cmd.append(" --def ");
 
7495
            cmd.append(defFileName);
 
7496
            cmd.append(" ");
 
7497
            }
 
7498
        if (impFileName.size()>0)
 
7499
            {
 
7500
            cmd.append(" --implib ");
 
7501
            cmd.append(impFileName);
 
7502
            cmd.append(" ");
 
7503
            }
 
7504
        for (unsigned int i=0 ; i<fileSet.size() ; i++)
 
7505
            {
 
7506
            String fname;
 
7507
            if (fileSetDir.size()>0)
 
7508
                {
 
7509
                fname.append(fileSetDir);
 
7510
                fname.append("/");
 
7511
                }
 
7512
            fname.append(fileSet[i]);
 
7513
            String fullName = parent.resolve(fname);
 
7514
 
 
7515
            cmd.append(" ");
 
7516
            cmd.append(fullName);
 
7517
            }
 
7518
        cmd.append(" ");
 
7519
        cmd.append(libs);
 
7520
 
 
7521
        String outString, errString;
 
7522
        if (!executeCommand(cmd.c_str(), "", outString, errString))
 
7523
            {
 
7524
            error("<sharedlib> problem: %s", errString.c_str());
 
7525
            return false;
 
7526
            }
 
7527
 
 
7528
        return true;
 
7529
        }
 
7530
 
 
7531
    virtual bool parse(Element *elem)
 
7532
        {
 
7533
        if (!parent.getAttribute(elem, "file", fileName))
 
7534
            return false;
 
7535
        if (!parent.getAttribute(elem, "import", impFileName))
 
7536
            return false;
 
7537
        if (!parent.getAttribute(elem, "def", defFileName))
 
7538
            return false;
 
7539
            
 
7540
        std::vector<Element *> children = elem->getChildren();
 
7541
        for (unsigned int i=0 ; i<children.size() ; i++)
 
7542
            {
 
7543
            Element *child = children[i];
 
7544
            String tagName = child->getName();
 
7545
            if (tagName == "fileset")
 
7546
                {
 
7547
                if (!parseFileSet(child, parent, fileSet))
 
7548
                    return false;
 
7549
                }
 
7550
            else if (tagName == "libs")
 
7551
                {
 
7552
                if (!parent.getValue(child, libs))
 
7553
                    return false;
 
7554
                libs = strip(libs);
 
7555
                }
 
7556
            }
 
7557
        return true;
 
7558
        }
 
7559
 
 
7560
private:
 
7561
 
 
7562
    String command;
 
7563
    String fileName;
 
7564
    String defFileName;
 
7565
    String impFileName;
 
7566
    FileSet fileSet;
 
7567
    String libs;
 
7568
 
 
7569
};
 
7570
 
 
7571
 
 
7572
 
 
7573
/**
 
7574
 * Run the "ar" command to archive .o's into a .a
 
7575
 */
 
7576
class TaskStaticLib : public Task
 
7577
{
 
7578
public:
 
7579
 
 
7580
    TaskStaticLib(MakeBase &par) : Task(par)
 
7581
        {
 
7582
        type = TASK_STATICLIB; name = "staticlib";
 
7583
        command = "ar crv";
 
7584
        }
 
7585
 
 
7586
    virtual ~TaskStaticLib()
 
7587
        {}
 
7588
 
 
7589
    virtual bool execute()
 
7590
        {
 
7591
        //trace("###########HERE %d", fileSet.size());
 
7592
        bool doit = false;
 
7593
        
 
7594
        String fullOut = parent.resolve(fileName);
 
7595
        //trace("ar fullout: %s", fullOut.c_str());
 
7596
        
 
7597
        if (!listFiles(parent, fileSet))
 
7598
            return false;
 
7599
        String fileSetDir = fileSet.getDirectory();
 
7600
 
 
7601
        for (unsigned int i=0 ; i<fileSet.size() ; i++)
 
7602
            {
 
7603
            String fname;
 
7604
            if (fileSetDir.size()>0)
 
7605
                {
 
7606
                fname.append(fileSetDir);
 
7607
                fname.append("/");
 
7608
                }
 
7609
            fname.append(fileSet[i]);
 
7610
            String fullName = parent.resolve(fname);
 
7611
            //trace("ar : %s/%s", fullOut.c_str(), fullName.c_str());
 
7612
            if (isNewerThan(fullName, fullOut))
 
7613
                doit = true;
 
7614
            }
 
7615
        //trace("Needs it:%d", doit);
 
7616
        if (!doit)
 
7617
            {
 
7618
            return true;
 
7619
            }
 
7620
 
 
7621
        String cmd = command;
 
7622
        cmd.append(" ");
 
7623
        cmd.append(fullOut);
 
7624
        for (unsigned int i=0 ; i<fileSet.size() ; i++)
 
7625
            {
 
7626
            String fname;
 
7627
            if (fileSetDir.size()>0)
 
7628
                {
 
7629
                fname.append(fileSetDir);
 
7630
                fname.append("/");
 
7631
                }
 
7632
            fname.append(fileSet[i]);
 
7633
            String fullName = parent.resolve(fname);
 
7634
 
 
7635
            cmd.append(" ");
 
7636
            cmd.append(fullName);
 
7637
            }
 
7638
 
 
7639
        String outString, errString;
 
7640
        if (!executeCommand(cmd.c_str(), "", outString, errString))
 
7641
            {
 
7642
            error("<staticlib> problem: %s", errString.c_str());
 
7643
            return false;
 
7644
            }
 
7645
 
 
7646
        return true;
 
7647
        }
 
7648
 
 
7649
 
 
7650
    virtual bool parse(Element *elem)
 
7651
        {
 
7652
        String s;
 
7653
        if (!parent.getAttribute(elem, "command", s))
 
7654
            return false;
 
7655
        if (s.size()>0)
 
7656
            command = s;
 
7657
        if (!parent.getAttribute(elem, "file", fileName))
 
7658
            return false;
 
7659
            
 
7660
        std::vector<Element *> children = elem->getChildren();
 
7661
        for (unsigned int i=0 ; i<children.size() ; i++)
 
7662
            {
 
7663
            Element *child = children[i];
 
7664
            String tagName = child->getName();
 
7665
            if (tagName == "fileset")
 
7666
                {
 
7667
                if (!parseFileSet(child, parent, fileSet))
 
7668
                    return false;
 
7669
                }
 
7670
            }
 
7671
        return true;
 
7672
        }
 
7673
 
 
7674
private:
 
7675
 
 
7676
    String command;
 
7677
    String fileName;
 
7678
    FileSet fileSet;
 
7679
 
 
7680
};
 
7681
 
 
7682
 
 
7683
 
 
7684
 
 
7685
/**
 
7686
 * Strip an executable
 
7687
 */
 
7688
class TaskStrip : public Task
 
7689
{
 
7690
public:
 
7691
 
 
7692
    TaskStrip(MakeBase &par) : Task(par)
 
7693
        { type = TASK_STRIP; name = "strip"; }
 
7694
 
 
7695
    virtual ~TaskStrip()
 
7696
        {}
 
7697
 
 
7698
    virtual bool execute()
 
7699
        {
 
7700
        String fullName = parent.resolve(fileName);
 
7701
        //trace("fullDir:%s", fullDir.c_str());
 
7702
        String cmd;
 
7703
        String outbuf, errbuf;
 
7704
 
 
7705
        if (symFileName.size()>0)
 
7706
            {
 
7707
            String symFullName = parent.resolve(symFileName);
 
7708
            cmd = "objcopy --only-keep-debug ";
 
7709
            cmd.append(getNativePath(fullName));
 
7710
            cmd.append(" ");
 
7711
            cmd.append(getNativePath(symFullName));
 
7712
            if (!executeCommand(cmd, "", outbuf, errbuf))
 
7713
                {
 
7714
                error("<strip> symbol file failed : %s", errbuf.c_str());
 
7715
                return false;
 
7716
                }
 
7717
            }
 
7718
            
 
7719
        cmd = "strip ";
 
7720
        cmd.append(getNativePath(fullName));
 
7721
        if (!executeCommand(cmd, "", outbuf, errbuf))
 
7722
            {
 
7723
            error("<strip> failed : %s", errbuf.c_str());
 
7724
            return false;
 
7725
            }
 
7726
        return true;
 
7727
        }
 
7728
 
 
7729
    virtual bool parse(Element *elem)
 
7730
        {
 
7731
        if (!parent.getAttribute(elem, "file", fileName))
 
7732
            return false;
 
7733
        if (!parent.getAttribute(elem, "symfile", symFileName))
 
7734
            return false;
 
7735
        if (fileName.size() == 0)
 
7736
            {
 
7737
            error("<strip> requires 'file=\"fileName\"' attribute");
 
7738
            return false;
 
7739
            }
 
7740
        return true;
 
7741
        }
 
7742
 
 
7743
private:
 
7744
 
 
7745
    String fileName;
 
7746
    String symFileName;
 
7747
};
 
7748
 
 
7749
 
 
7750
/**
 
7751
 *
 
7752
 */
 
7753
class TaskTouch : public Task
 
7754
{
 
7755
public:
 
7756
 
 
7757
    TaskTouch(MakeBase &par) : Task(par)
 
7758
        { type = TASK_TOUCH; name = "touch"; }
 
7759
 
 
7760
    virtual ~TaskTouch()
 
7761
        {}
 
7762
 
 
7763
    virtual bool execute()
 
7764
        {
 
7765
        String fullName = parent.resolve(fileName);
 
7766
        String nativeFile = getNativePath(fullName);
 
7767
        if (!isRegularFile(fullName) && !isDirectory(fullName))
 
7768
            {            
 
7769
            // S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
 
7770
            int ret = creat(nativeFile.c_str(), 0666);
 
7771
            if (ret != 0) 
 
7772
                {
 
7773
                error("<touch> could not create '%s' : %s",
 
7774
                    nativeFile.c_str(), strerror(ret));
 
7775
                return false;
 
7776
                }
 
7777
            return true;
 
7778
            }
 
7779
        int ret = utime(nativeFile.c_str(), (struct utimbuf *)0);
 
7780
        if (ret != 0)
 
7781
            {
 
7782
            error("<touch> could not update the modification time for '%s' : %s",
 
7783
                nativeFile.c_str(), strerror(ret));
 
7784
            return false;
 
7785
            }
 
7786
        return true;
 
7787
        }
 
7788
 
 
7789
    virtual bool parse(Element *elem)
 
7790
        {
 
7791
        //trace("touch parse");
 
7792
        if (!parent.getAttribute(elem, "file", fileName))
 
7793
            return false;
 
7794
        if (fileName.size() == 0)
 
7795
            {
 
7796
            error("<touch> requires 'file=\"fileName\"' attribute");
 
7797
            return false;
 
7798
            }
 
7799
        return true;
 
7800
        }
 
7801
 
 
7802
    String fileName;
 
7803
};
 
7804
 
 
7805
 
 
7806
/**
 
7807
 *
 
7808
 */
 
7809
class TaskTstamp : public Task
 
7810
{
 
7811
public:
 
7812
 
 
7813
    TaskTstamp(MakeBase &par) : Task(par)
 
7814
        { type = TASK_TSTAMP; name = "tstamp"; }
 
7815
 
 
7816
    virtual ~TaskTstamp()
 
7817
        {}
 
7818
 
 
7819
    virtual bool execute()
 
7820
        {
 
7821
        return true;
 
7822
        }
 
7823
 
 
7824
    virtual bool parse(Element *elem)
 
7825
        {
 
7826
        //trace("tstamp parse");
 
7827
        return true;
 
7828
        }
 
7829
};
 
7830
 
 
7831
 
 
7832
 
 
7833
/**
 
7834
 *
 
7835
 */
 
7836
Task *Task::createTask(Element *elem, int lineNr)
 
7837
{
 
7838
    String tagName = elem->getName();
 
7839
    //trace("task:%s", tagName.c_str());
 
7840
    Task *task = NULL;
 
7841
    if (tagName == "cc")
 
7842
        task = new TaskCC(parent);
 
7843
    else if (tagName == "copy")
 
7844
        task = new TaskCopy(parent);
 
7845
    else if (tagName == "delete")
 
7846
        task = new TaskDelete(parent);
 
7847
    else if (tagName == "jar")
 
7848
        task = new TaskJar(parent);
 
7849
    else if (tagName == "javac")
 
7850
        task = new TaskJavac(parent);
 
7851
    else if (tagName == "link")
 
7852
        task = new TaskLink(parent);
 
7853
    else if (tagName == "makefile")
 
7854
        task = new TaskMakeFile(parent);
 
7855
    else if (tagName == "mkdir")
 
7856
        task = new TaskMkDir(parent);
 
7857
    else if (tagName == "msgfmt")
 
7858
        task = new TaskMsgFmt(parent);
 
7859
    else if (tagName == "pkg-config")
 
7860
        task = new TaskPkgConfig(parent);
 
7861
    else if (tagName == "ranlib")
 
7862
        task = new TaskRanlib(parent);
 
7863
    else if (tagName == "rc")
 
7864
        task = new TaskRC(parent);
 
7865
    else if (tagName == "sharedlib")
 
7866
        task = new TaskSharedLib(parent);
 
7867
    else if (tagName == "staticlib")
 
7868
        task = new TaskStaticLib(parent);
 
7869
    else if (tagName == "strip")
 
7870
        task = new TaskStrip(parent);
 
7871
    else if (tagName == "touch")
 
7872
        task = new TaskTouch(parent);
 
7873
    else if (tagName == "tstamp")
 
7874
        task = new TaskTstamp(parent);
 
7875
    else
 
7876
        {
 
7877
        error("Unknown task '%s'", tagName.c_str());
 
7878
        return NULL;
 
7879
        }
 
7880
 
 
7881
    task->setLine(lineNr);
 
7882
 
 
7883
    if (!task->parse(elem))
 
7884
        {
 
7885
        delete task;
 
7886
        return NULL;
 
7887
        }
 
7888
    return task;
 
7889
}
 
7890
 
 
7891
 
 
7892
 
 
7893
//########################################################################
 
7894
//# T A R G E T
 
7895
//########################################################################
 
7896
 
 
7897
/**
 
7898
 *
 
7899
 */
 
7900
class Target : public MakeBase
 
7901
{
 
7902
 
 
7903
public:
 
7904
 
 
7905
    /**
 
7906
     *
 
7907
     */
 
7908
    Target(Make &par) : parent(par)
 
7909
        { init(); }
 
7910
 
 
7911
    /**
 
7912
     *
 
7913
     */
 
7914
    Target(const Target &other) : parent(other.parent)
 
7915
        { init(); assign(other); }
 
7916
 
 
7917
    /**
 
7918
     *
 
7919
     */
 
7920
    Target &operator=(const Target &other)
 
7921
        { init(); assign(other); return *this; }
 
7922
 
 
7923
    /**
 
7924
     *
 
7925
     */
 
7926
    virtual ~Target()
 
7927
        { cleanup() ; }
 
7928
 
 
7929
 
 
7930
    /**
 
7931
     *
 
7932
     */
 
7933
    virtual Make &getParent()
 
7934
        { return parent; }
 
7935
 
 
7936
    /**
 
7937
     *
 
7938
     */
 
7939
    virtual String getName()
 
7940
        { return name; }
 
7941
 
 
7942
    /**
 
7943
     *
 
7944
     */
 
7945
    virtual void setName(const String &val)
 
7946
        { name = val; }
 
7947
 
 
7948
    /**
 
7949
     *
 
7950
     */
 
7951
    virtual String getDescription()
 
7952
        { return description; }
 
7953
 
 
7954
    /**
 
7955
     *
 
7956
     */
 
7957
    virtual void setDescription(const String &val)
 
7958
        { description = val; }
 
7959
 
 
7960
    /**
 
7961
     *
 
7962
     */
 
7963
    virtual void addDependency(const String &val)
 
7964
        { deps.push_back(val); }
 
7965
 
 
7966
    /**
 
7967
     *
 
7968
     */
 
7969
    virtual void parseDependencies(const String &val)
 
7970
        { deps = tokenize(val, ", "); }
 
7971
 
 
7972
    /**
 
7973
     *
 
7974
     */
 
7975
    virtual std::vector<String> &getDependencies()
 
7976
        { return deps; }
 
7977
 
 
7978
    /**
 
7979
     *
 
7980
     */
 
7981
    virtual String getIf()
 
7982
        { return ifVar; }
 
7983
 
 
7984
    /**
 
7985
     *
 
7986
     */
 
7987
    virtual void setIf(const String &val)
 
7988
        { ifVar = val; }
 
7989
 
 
7990
    /**
 
7991
     *
 
7992
     */
 
7993
    virtual String getUnless()
 
7994
        { return unlessVar; }
 
7995
 
 
7996
    /**
 
7997
     *
 
7998
     */
 
7999
    virtual void setUnless(const String &val)
 
8000
        { unlessVar = val; }
 
8001
 
 
8002
    /**
 
8003
     *
 
8004
     */
 
8005
    virtual void addTask(Task *val)
 
8006
        { tasks.push_back(val); }
 
8007
 
 
8008
    /**
 
8009
     *
 
8010
     */
 
8011
    virtual std::vector<Task *> &getTasks()
 
8012
        { return tasks; }
 
8013
 
 
8014
private:
 
8015
 
 
8016
    void init()
 
8017
        {
 
8018
        }
 
8019
 
 
8020
    void cleanup()
 
8021
        {
 
8022
        tasks.clear();
 
8023
        }
 
8024
 
 
8025
    void assign(const Target &other)
 
8026
        {
 
8027
        //parent      = other.parent;
 
8028
        name        = other.name;
 
8029
        description = other.description;
 
8030
        ifVar       = other.ifVar;
 
8031
        unlessVar   = other.unlessVar;
 
8032
        deps        = other.deps;
 
8033
        tasks       = other.tasks;
 
8034
        }
 
8035
 
 
8036
    Make &parent;
 
8037
 
 
8038
    String name;
 
8039
 
 
8040
    String description;
 
8041
 
 
8042
    String ifVar;
 
8043
 
 
8044
    String unlessVar;
 
8045
 
 
8046
    std::vector<String> deps;
 
8047
 
 
8048
    std::vector<Task *> tasks;
 
8049
 
 
8050
};
 
8051
 
 
8052
 
 
8053
 
 
8054
 
 
8055
 
 
8056
 
 
8057
 
 
8058
 
 
8059
//########################################################################
 
8060
//# M A K E
 
8061
//########################################################################
 
8062
 
 
8063
 
 
8064
/**
 
8065
 *
 
8066
 */
 
8067
class Make : public MakeBase
 
8068
{
 
8069
 
 
8070
public:
 
8071
 
 
8072
    /**
 
8073
     *
 
8074
     */
 
8075
    Make()
 
8076
        { init(); }
 
8077
 
 
8078
    /**
 
8079
     *
 
8080
     */
 
8081
    Make(const Make &other)
 
8082
        { assign(other); }
 
8083
 
 
8084
    /**
 
8085
     *
 
8086
     */
 
8087
    Make &operator=(const Make &other)
 
8088
        { assign(other); return *this; }
 
8089
 
 
8090
    /**
 
8091
     *
 
8092
     */
 
8093
    virtual ~Make()
 
8094
        { cleanup(); }
 
8095
 
 
8096
    /**
 
8097
     *
 
8098
     */
 
8099
    virtual std::map<String, Target> &getTargets()
 
8100
        { return targets; }
 
8101
 
 
8102
 
 
8103
    /**
 
8104
     *
 
8105
     */
 
8106
    virtual String version()
 
8107
        { return BUILDTOOL_VERSION; }
 
8108
 
 
8109
    /**
 
8110
     * Overload a <property>
 
8111
     */
 
8112
    virtual bool specifyProperty(const String &name,
 
8113
                                 const String &value);
 
8114
 
 
8115
    /**
 
8116
     *
 
8117
     */
 
8118
    virtual bool run();
 
8119
 
 
8120
    /**
 
8121
     *
 
8122
     */
 
8123
    virtual bool run(const String &target);
 
8124
 
 
8125
 
 
8126
 
 
8127
private:
 
8128
 
 
8129
    /**
 
8130
     *
 
8131
     */
 
8132
    void init();
 
8133
 
 
8134
    /**
 
8135
     *
 
8136
     */
 
8137
    void cleanup();
 
8138
 
 
8139
    /**
 
8140
     *
 
8141
     */
 
8142
    void assign(const Make &other);
 
8143
 
 
8144
    /**
 
8145
     *
 
8146
     */
 
8147
    bool executeTask(Task &task);
 
8148
 
 
8149
 
 
8150
    /**
 
8151
     *
 
8152
     */
 
8153
    bool executeTarget(Target &target,
 
8154
             std::set<String> &targetsCompleted);
 
8155
 
 
8156
 
 
8157
    /**
 
8158
     *
 
8159
     */
 
8160
    bool execute();
 
8161
 
 
8162
    /**
 
8163
     *
 
8164
     */
 
8165
    bool checkTargetDependencies(Target &prop,
 
8166
                    std::vector<String> &depList);
 
8167
 
 
8168
    /**
 
8169
     *
 
8170
     */
 
8171
    bool parsePropertyFile(const String &fileName,
 
8172
                           const String &prefix);
 
8173
 
 
8174
    /**
 
8175
     *
 
8176
     */
 
8177
    bool parseProperty(Element *elem);
 
8178
 
 
8179
    /**
 
8180
     *
 
8181
     */
 
8182
    bool parseFile();
 
8183
 
 
8184
    /**
 
8185
     *
 
8186
     */
 
8187
    std::vector<String> glob(const String &pattern);
 
8188
 
 
8189
 
 
8190
    //###############
 
8191
    //# Fields
 
8192
    //###############
 
8193
 
 
8194
    String projectName;
 
8195
 
 
8196
    String currentTarget;
 
8197
 
 
8198
    String defaultTarget;
 
8199
 
 
8200
    String specifiedTarget;
 
8201
 
 
8202
    String baseDir;
 
8203
 
 
8204
    String description;
 
8205
    
 
8206
    //std::vector<Property> properties;
 
8207
    
 
8208
    std::map<String, Target> targets;
 
8209
 
 
8210
    std::vector<Task *> allTasks;
 
8211
    
 
8212
    std::map<String, String> specifiedProperties;
 
8213
 
 
8214
};
 
8215
 
 
8216
 
 
8217
//########################################################################
 
8218
//# C L A S S  M A I N T E N A N C E
 
8219
//########################################################################
 
8220
 
 
8221
/**
 
8222
 *
 
8223
 */
 
8224
void Make::init()
 
8225
{
 
8226
    uri             = "build.xml";
 
8227
    projectName     = "";
 
8228
    currentTarget   = "";
 
8229
    defaultTarget   = "";
 
8230
    specifiedTarget = "";
 
8231
    baseDir         = "";
 
8232
    description     = "";
 
8233
    envPrefix       = "";
 
8234
    properties.clear();
 
8235
    for (unsigned int i = 0 ; i < allTasks.size() ; i++)
 
8236
        delete allTasks[i];
 
8237
    allTasks.clear();
 
8238
}
 
8239
 
 
8240
 
 
8241
 
 
8242
/**
 
8243
 *
 
8244
 */
 
8245
void Make::cleanup()
 
8246
{
 
8247
    for (unsigned int i = 0 ; i < allTasks.size() ; i++)
 
8248
        delete allTasks[i];
 
8249
    allTasks.clear();
 
8250
}
 
8251
 
 
8252
 
 
8253
 
 
8254
/**
 
8255
 *
 
8256
 */
 
8257
void Make::assign(const Make &other)
 
8258
{
 
8259
    uri              = other.uri;
 
8260
    projectName      = other.projectName;
 
8261
    currentTarget    = other.currentTarget;
 
8262
    defaultTarget    = other.defaultTarget;
 
8263
    specifiedTarget  = other.specifiedTarget;
 
8264
    baseDir          = other.baseDir;
 
8265
    description      = other.description;
 
8266
    properties       = other.properties;
 
8267
}
 
8268
 
 
8269
 
 
8270
 
 
8271
//########################################################################
 
8272
//# U T I L I T Y    T A S K S
 
8273
//########################################################################
 
8274
 
 
8275
/**
 
8276
 *  Perform a file globbing
 
8277
 */
 
8278
std::vector<String> Make::glob(const String &pattern)
 
8279
{
 
8280
    std::vector<String> res;
 
8281
    return res;
 
8282
}
 
8283
 
 
8284
 
 
8285
//########################################################################
 
8286
//# P U B L I C    A P I
 
8287
//########################################################################
 
8288
 
 
8289
 
 
8290
 
 
8291
/**
 
8292
 *
 
8293
 */
 
8294
bool Make::executeTarget(Target &target,
 
8295
             std::set<String> &targetsCompleted)
 
8296
{
 
8297
 
 
8298
    String name = target.getName();
 
8299
 
 
8300
    //First get any dependencies for this target
 
8301
    std::vector<String> deps = target.getDependencies();
 
8302
    for (unsigned int i=0 ; i<deps.size() ; i++)
 
8303
        {
 
8304
        String dep = deps[i];
 
8305
        //Did we do it already?  Skip
 
8306
        if (targetsCompleted.find(dep)!=targetsCompleted.end())
 
8307
            continue;
 
8308
            
 
8309
        std::map<String, Target> &tgts =
 
8310
               target.getParent().getTargets();
 
8311
        std::map<String, Target>::iterator iter =
 
8312
               tgts.find(dep);
 
8313
        if (iter == tgts.end())
 
8314
            {
 
8315
            error("Target '%s' dependency '%s' not found",
 
8316
                      name.c_str(),  dep.c_str());
 
8317
            return false;
 
8318
            }
 
8319
        Target depTarget = iter->second;
 
8320
        if (!executeTarget(depTarget, targetsCompleted))
 
8321
            {
 
8322
            return false;
 
8323
            }
 
8324
        }
 
8325
 
 
8326
    status("## Target : %s : %s", name.c_str(),
 
8327
            target.getDescription().c_str());
 
8328
 
 
8329
    //Now let's do the tasks
 
8330
    std::vector<Task *> &tasks = target.getTasks();
 
8331
    for (unsigned int i=0 ; i<tasks.size() ; i++)
 
8332
        {
 
8333
        Task *task = tasks[i];
 
8334
        status("---- task : %s", task->getName().c_str());
 
8335
        if (!task->execute())
 
8336
            {
 
8337
            return false;
 
8338
            }
 
8339
        }
 
8340
        
 
8341
    targetsCompleted.insert(name);
 
8342
    
 
8343
    return true;
 
8344
}
 
8345
 
 
8346
 
 
8347
 
 
8348
/**
 
8349
 *  Main execute() method.  Start here and work
 
8350
 *  up the dependency tree 
 
8351
 */
 
8352
bool Make::execute()
 
8353
{
 
8354
    status("######## EXECUTE");
 
8355
 
 
8356
    //Determine initial target
 
8357
    if (specifiedTarget.size()>0)
 
8358
        {
 
8359
        currentTarget = specifiedTarget;
 
8360
        }
 
8361
    else if (defaultTarget.size()>0)
 
8362
        {
 
8363
        currentTarget = defaultTarget;
 
8364
        }
 
8365
    else
 
8366
        {
 
8367
        error("execute: no specified or default target requested");
 
8368
        return false;
 
8369
        }
 
8370
 
 
8371
    std::map<String, Target>::iterator iter =
 
8372
               targets.find(currentTarget);
 
8373
    if (iter == targets.end())
 
8374
        {
 
8375
        error("Initial target '%s' not found",
 
8376
                 currentTarget.c_str());
 
8377
        return false;
 
8378
        }
 
8379
        
 
8380
    //Now run
 
8381
    Target target = iter->second;
 
8382
    std::set<String> targetsCompleted;
 
8383
    if (!executeTarget(target, targetsCompleted))
 
8384
        {
 
8385
        return false;
 
8386
        }
 
8387
 
 
8388
    status("######## EXECUTE COMPLETE");
 
8389
    return true;
 
8390
}
 
8391
 
 
8392
 
 
8393
 
 
8394
 
 
8395
/**
 
8396
 *
 
8397
 */
 
8398
bool Make::checkTargetDependencies(Target &target, 
 
8399
                            std::vector<String> &depList)
 
8400
{
 
8401
    String tgtName = target.getName().c_str();
 
8402
    depList.push_back(tgtName);
 
8403
 
 
8404
    std::vector<String> deps = target.getDependencies();
 
8405
    for (unsigned int i=0 ; i<deps.size() ; i++)
 
8406
        {
 
8407
        String dep = deps[i];
 
8408
        //First thing entered was the starting Target
 
8409
        if (dep == depList[0])
 
8410
            {
 
8411
            error("Circular dependency '%s' found at '%s'",
 
8412
                      dep.c_str(), tgtName.c_str());
 
8413
            std::vector<String>::iterator diter;
 
8414
            for (diter=depList.begin() ; diter!=depList.end() ; diter++)
 
8415
                {
 
8416
                error("  %s", diter->c_str());
 
8417
                }
 
8418
            return false;
 
8419
            }
 
8420
 
 
8421
        std::map<String, Target> &tgts =
 
8422
                  target.getParent().getTargets();
 
8423
        std::map<String, Target>::iterator titer = tgts.find(dep);
 
8424
        if (titer == tgts.end())
 
8425
            {
 
8426
            error("Target '%s' dependency '%s' not found",
 
8427
                      tgtName.c_str(), dep.c_str());
 
8428
            return false;
 
8429
            }
 
8430
        if (!checkTargetDependencies(titer->second, depList))
 
8431
            {
 
8432
            return false;
 
8433
            }
 
8434
        }
 
8435
    return true;
 
8436
}
 
8437
 
 
8438
 
 
8439
 
 
8440
 
 
8441
 
 
8442
static int getword(int pos, const String &inbuf, String &result)
 
8443
{
 
8444
    int p = pos;
 
8445
    int len = (int)inbuf.size();
 
8446
    String val;
 
8447
    while (p < len)
 
8448
        {
 
8449
        char ch = inbuf[p];
 
8450
        if (!isalnum(ch) && ch!='.' && ch!='_')
 
8451
            break;
 
8452
        val.push_back(ch);
 
8453
        p++;
 
8454
        }
 
8455
    result = val;
 
8456
    return p;
 
8457
}
 
8458
 
 
8459
 
 
8460
 
 
8461
 
 
8462
/**
 
8463
 *
 
8464
 */
 
8465
bool Make::parsePropertyFile(const String &fileName,
 
8466
                             const String &prefix)
 
8467
{
 
8468
    FILE *f = fopen(fileName.c_str(), "r");
 
8469
    if (!f)
 
8470
        {
 
8471
        error("could not open property file %s", fileName.c_str());
 
8472
        return false;
 
8473
        }
 
8474
    int linenr = 0;
 
8475
    while (!feof(f))
 
8476
        {
 
8477
        char buf[256];
 
8478
        if (!fgets(buf, 255, f))
 
8479
            break;
 
8480
        linenr++;
 
8481
        String s = buf;
 
8482
        s = trim(s);
 
8483
        int len = s.size();
 
8484
        if (len == 0)
 
8485
            continue;
 
8486
        if (s[0] == '#')
 
8487
            continue;
 
8488
        String key;
 
8489
        String val;
 
8490
        int p = 0;
 
8491
        int p2 = getword(p, s, key);
 
8492
        if (p2 <= p)
 
8493
            {
 
8494
            error("property file %s, line %d: expected keyword",
 
8495
                    fileName.c_str(), linenr);
 
8496
            return false;
 
8497
            }
 
8498
        if (prefix.size() > 0)
 
8499
            {
 
8500
            key.insert(0, prefix);
 
8501
            }
 
8502
 
 
8503
        //skip whitespace
 
8504
        for (p=p2 ; p<len ; p++)
 
8505
            if (!isspace(s[p]))
 
8506
                break;
 
8507
 
 
8508
        if (p>=len || s[p]!='=')
 
8509
            {
 
8510
            error("property file %s, line %d: expected '='",
 
8511
                    fileName.c_str(), linenr);
 
8512
            return false;
 
8513
            }
 
8514
        p++;
 
8515
 
 
8516
        //skip whitespace
 
8517
        for ( ; p<len ; p++)
 
8518
            if (!isspace(s[p]))
 
8519
                break;
 
8520
 
 
8521
        /* This way expects a word after the =
 
8522
        p2 = getword(p, s, val);
 
8523
        if (p2 <= p)
 
8524
            {
 
8525
            error("property file %s, line %d: expected value",
 
8526
                    fileName.c_str(), linenr);
 
8527
            return false;
 
8528
            }
 
8529
        */
 
8530
        // This way gets the rest of the line after the =
 
8531
        if (p>=len)
 
8532
            {
 
8533
            error("property file %s, line %d: expected value",
 
8534
                    fileName.c_str(), linenr);
 
8535
            return false;
 
8536
            }
 
8537
        val = s.substr(p);
 
8538
        if (key.size()==0)
 
8539
            continue;
 
8540
        //allow property to be set, even if val=""
 
8541
 
 
8542
        //trace("key:'%s' val:'%s'", key.c_str(), val.c_str());
 
8543
        //See if we wanted to overload this property
 
8544
        std::map<String, String>::iterator iter =
 
8545
            specifiedProperties.find(key);
 
8546
        if (iter!=specifiedProperties.end())
 
8547
            {
 
8548
            val = iter->second;
 
8549
            status("overloading property '%s' = '%s'",
 
8550
                   key.c_str(), val.c_str());
 
8551
            }
 
8552
        properties[key] = val;
 
8553
        }
 
8554
    fclose(f);
 
8555
    return true;
 
8556
}
 
8557
 
 
8558
 
 
8559
 
 
8560
 
 
8561
/**
 
8562
 *
 
8563
 */
 
8564
bool Make::parseProperty(Element *elem)
 
8565
{
 
8566
    std::vector<Attribute> &attrs = elem->getAttributes();
 
8567
    for (unsigned int i=0 ; i<attrs.size() ; i++)
 
8568
        {
 
8569
        String attrName = attrs[i].getName();
 
8570
        String attrVal  = attrs[i].getValue();
 
8571
 
 
8572
        if (attrName == "name")
 
8573
            {
 
8574
            String val;
 
8575
            if (!getAttribute(elem, "value", val))
 
8576
                return false;
 
8577
            if (val.size() > 0)
 
8578
                {
 
8579
                properties[attrVal] = val;
 
8580
                }
 
8581
            else
 
8582
                {
 
8583
                if (!getAttribute(elem, "location", val))
 
8584
                    return false;
 
8585
                //let the property exist, even if not defined
 
8586
                properties[attrVal] = val;
 
8587
                }
 
8588
            //See if we wanted to overload this property
 
8589
            std::map<String, String>::iterator iter =
 
8590
                specifiedProperties.find(attrVal);
 
8591
            if (iter != specifiedProperties.end())
 
8592
                {
 
8593
                val = iter->second;
 
8594
                status("overloading property '%s' = '%s'",
 
8595
                    attrVal.c_str(), val.c_str());
 
8596
                properties[attrVal] = val;
 
8597
                }
 
8598
            }
 
8599
        else if (attrName == "file")
 
8600
            {
 
8601
            String prefix;
 
8602
            if (!getAttribute(elem, "prefix", prefix))
 
8603
                return false;
 
8604
            if (prefix.size() > 0)
 
8605
                {
 
8606
                if (prefix[prefix.size()-1] != '.')
 
8607
                    prefix.push_back('.');
 
8608
                }
 
8609
            if (!parsePropertyFile(attrName, prefix))
 
8610
                return false;
 
8611
            }
 
8612
        else if (attrName == "environment")
 
8613
            {
 
8614
            if (envPrefix.size() > 0)
 
8615
                {
 
8616
                error("environment prefix can only be set once");
 
8617
                return false;
 
8618
                }
 
8619
            if (attrVal.find('.') != attrVal.npos)
 
8620
                {
 
8621
                error("environment prefix cannot have a '.' in it");
 
8622
                return false;
 
8623
                }
 
8624
            envPrefix = attrVal;
 
8625
            envPrefix.push_back('.');
 
8626
            }
 
8627
        }
 
8628
 
 
8629
    return true;
 
8630
}
 
8631
 
 
8632
 
 
8633
 
 
8634
 
 
8635
/**
 
8636
 *
 
8637
 */
 
8638
bool Make::parseFile()
 
8639
{
 
8640
    status("######## PARSE : %s", uri.getPath().c_str());
 
8641
 
 
8642
    setLine(0);
 
8643
 
 
8644
    Parser parser;
 
8645
    Element *root = parser.parseFile(uri.getNativePath());
 
8646
    if (!root)
 
8647
        {
 
8648
        error("Could not open %s for reading",
 
8649
              uri.getNativePath().c_str());
 
8650
        return false;
 
8651
        }
 
8652
    
 
8653
    setLine(root->getLine());
 
8654
 
 
8655
    if (root->getChildren().size()==0 ||
 
8656
        root->getChildren()[0]->getName()!="project")
 
8657
        {
 
8658
        error("Main xml element should be <project>");
 
8659
        delete root;
 
8660
        return false;
 
8661
        }
 
8662
 
 
8663
    //########## Project attributes
 
8664
    Element *project = root->getChildren()[0];
 
8665
    String s = project->getAttribute("name");
 
8666
    if (s.size() > 0)
 
8667
        projectName = s;
 
8668
    s = project->getAttribute("default");
 
8669
    if (s.size() > 0)
 
8670
        defaultTarget = s;
 
8671
    s = project->getAttribute("basedir");
 
8672
    if (s.size() > 0)
 
8673
        baseDir = s;
 
8674
 
 
8675
    //######### PARSE MEMBERS
 
8676
    std::vector<Element *> children = project->getChildren();
 
8677
    for (unsigned int i=0 ; i<children.size() ; i++)
 
8678
        {
 
8679
        Element *elem = children[i];
 
8680
        setLine(elem->getLine());
 
8681
        String tagName = elem->getName();
 
8682
 
 
8683
        //########## DESCRIPTION
 
8684
        if (tagName == "description")
 
8685
            {
 
8686
            description = parser.trim(elem->getValue());
 
8687
            }
 
8688
 
 
8689
        //######### PROPERTY
 
8690
        else if (tagName == "property")
 
8691
            {
 
8692
            if (!parseProperty(elem))
 
8693
                return false;
 
8694
            }
 
8695
 
 
8696
        //######### TARGET
 
8697
        else if (tagName == "target")
 
8698
            {
 
8699
            String tname   = elem->getAttribute("name");
 
8700
            String tdesc   = elem->getAttribute("description");
 
8701
            String tdeps   = elem->getAttribute("depends");
 
8702
            String tif     = elem->getAttribute("if");
 
8703
            String tunless = elem->getAttribute("unless");
 
8704
            Target target(*this);
 
8705
            target.setName(tname);
 
8706
            target.setDescription(tdesc);
 
8707
            target.parseDependencies(tdeps);
 
8708
            target.setIf(tif);
 
8709
            target.setUnless(tunless);
 
8710
            std::vector<Element *> telems = elem->getChildren();
 
8711
            for (unsigned int i=0 ; i<telems.size() ; i++)
 
8712
                {
 
8713
                Element *telem = telems[i];
 
8714
                Task breeder(*this);
 
8715
                Task *task = breeder.createTask(telem, telem->getLine());
 
8716
                if (!task)
 
8717
                    return false;
 
8718
                allTasks.push_back(task);
 
8719
                target.addTask(task);
 
8720
                }
 
8721
 
 
8722
            //Check name
 
8723
            if (tname.size() == 0)
 
8724
                {
 
8725
                error("no name for target");
 
8726
                return false;
 
8727
                }
 
8728
            //Check for duplicate name
 
8729
            if (targets.find(tname) != targets.end())
 
8730
                {
 
8731
                error("target '%s' already defined", tname.c_str());
 
8732
                return false;
 
8733
                }
 
8734
            //more work than targets[tname]=target, but avoids default allocator
 
8735
            targets.insert(std::make_pair<String, Target>(tname, target));
 
8736
            }
 
8737
        //######### none of the above
 
8738
        else
 
8739
            {
 
8740
            error("unknown toplevel tag: <%s>", tagName.c_str());
 
8741
            return false;
 
8742
            }
 
8743
 
 
8744
        }
 
8745
 
 
8746
    std::map<String, Target>::iterator iter;
 
8747
    for (iter = targets.begin() ; iter!= targets.end() ; iter++)
 
8748
        {
 
8749
        Target tgt = iter->second;
 
8750
        std::vector<String> depList;
 
8751
        if (!checkTargetDependencies(tgt, depList))
 
8752
            {
 
8753
            return false;
 
8754
            }
 
8755
        }
 
8756
 
 
8757
 
 
8758
    delete root;
 
8759
    status("######## PARSE COMPLETE");
 
8760
    return true;
 
8761
}
 
8762
 
 
8763
 
 
8764
/**
 
8765
 * Overload a <property>
 
8766
 */
 
8767
bool Make::specifyProperty(const String &name, const String &value)
 
8768
{
 
8769
    if (specifiedProperties.find(name) != specifiedProperties.end())
 
8770
        {
 
8771
        error("Property %s already specified", name.c_str());
 
8772
        return false;
 
8773
        }
 
8774
    specifiedProperties[name] = value;
 
8775
    return true;
 
8776
}
 
8777
 
 
8778
 
 
8779
 
 
8780
/**
 
8781
 *
 
8782
 */
 
8783
bool Make::run()
 
8784
{
 
8785
    if (!parseFile())
 
8786
        return false;
 
8787
        
 
8788
    if (!execute())
 
8789
        return false;
 
8790
 
 
8791
    return true;
 
8792
}
 
8793
 
 
8794
 
 
8795
 
 
8796
 
 
8797
/**
 
8798
 * Get a formatted MM:SS.sss time elapsed string
 
8799
 */ 
 
8800
static String
 
8801
timeDiffString(struct timeval &x, struct timeval &y)
 
8802
{
 
8803
    long microsX  = x.tv_usec;
 
8804
    long secondsX = x.tv_sec;
 
8805
    long microsY  = y.tv_usec;
 
8806
    long secondsY = y.tv_sec;
 
8807
    if (microsX < microsY)
 
8808
        {
 
8809
        microsX += 1000000;
 
8810
        secondsX -= 1;
 
8811
        }
 
8812
 
 
8813
    int seconds = (int)(secondsX - secondsY);
 
8814
    int millis  = (int)((microsX - microsY)/1000);
 
8815
 
 
8816
    int minutes = seconds/60;
 
8817
    seconds -= minutes*60;
 
8818
    char buf[80];
 
8819
    snprintf(buf, 79, "%dm %d.%03ds", minutes, seconds, millis);
 
8820
    String ret = buf;
 
8821
    return ret;
 
8822
    
 
8823
}
 
8824
 
 
8825
/**
 
8826
 *
 
8827
 */
 
8828
bool Make::run(const String &target)
 
8829
{
 
8830
    status("####################################################");
 
8831
    status("#   %s", version().c_str());
 
8832
    status("####################################################");
 
8833
    struct timeval timeStart, timeEnd;
 
8834
    ::gettimeofday(&timeStart, NULL);
 
8835
    specifiedTarget = target;
 
8836
    if (!run())
 
8837
        return false;
 
8838
    ::gettimeofday(&timeEnd, NULL);
 
8839
    String timeStr = timeDiffString(timeEnd, timeStart);
 
8840
    status("####################################################");
 
8841
    status("#   BuildTool Completed : %s", timeStr.c_str());
 
8842
    status("####################################################");
 
8843
    return true;
 
8844
}
 
8845
 
 
8846
 
 
8847
 
 
8848
 
 
8849
 
 
8850
 
 
8851
 
 
8852
}// namespace buildtool
 
8853
//########################################################################
 
8854
//# M A I N
 
8855
//########################################################################
 
8856
 
 
8857
typedef buildtool::String String;
 
8858
 
 
8859
/**
 
8860
 *  Format an error message in printf() style
 
8861
 */
 
8862
static void error(const char *fmt, ...)
 
8863
{
 
8864
    va_list ap;
 
8865
    va_start(ap, fmt);
 
8866
    fprintf(stderr, "BuildTool error: ");
 
8867
    vfprintf(stderr, fmt, ap);
 
8868
    fprintf(stderr, "\n");
 
8869
    va_end(ap);
 
8870
}
 
8871
 
 
8872
 
 
8873
static bool parseProperty(const String &s, String &name, String &val)
 
8874
{
 
8875
    int len = s.size();
 
8876
    int i;
 
8877
    for (i=0 ; i<len ; i++)
 
8878
        {
 
8879
        char ch = s[i];
 
8880
        if (ch == '=')
 
8881
            break;
 
8882
        name.push_back(ch);
 
8883
        }
 
8884
    if (i>=len || s[i]!='=')
 
8885
        {
 
8886
        error("property requires -Dname=value");
 
8887
        return false;
 
8888
        }
 
8889
    i++;
 
8890
    for ( ; i<len ; i++)
 
8891
        {
 
8892
        char ch = s[i];
 
8893
        val.push_back(ch);
 
8894
        }
 
8895
    return true;
 
8896
}
 
8897
 
 
8898
 
 
8899
/**
 
8900
 * Compare a buffer with a key, for the length of the key
 
8901
 */
 
8902
static bool sequ(const String &buf, const char *key)
 
8903
{
 
8904
    int len = buf.size();
 
8905
    for (int i=0 ; key[i] && i<len ; i++)
 
8906
        {
 
8907
        if (key[i] != buf[i])
 
8908
            return false;
 
8909
        }        
 
8910
    return true;
 
8911
}
 
8912
 
 
8913
static void usage(int argc, char **argv)
 
8914
{
 
8915
    printf("usage:\n");
 
8916
    printf("   %s [options] [target]\n", argv[0]);
 
8917
    printf("Options:\n");
 
8918
    printf("  -help, -h              print this message\n");
 
8919
    printf("  -version               print the version information and exit\n");
 
8920
    printf("  -file <file>           use given buildfile\n");
 
8921
    printf("  -f <file>                 ''\n");
 
8922
    printf("  -D<property>=<value>   use value for given property\n");
 
8923
}
 
8924
 
 
8925
 
 
8926
 
 
8927
 
 
8928
/**
 
8929
 * Parse the command-line args, get our options,
 
8930
 * and run this thing
 
8931
 */   
 
8932
static bool parseOptions(int argc, char **argv)
 
8933
{
 
8934
    if (argc < 1)
 
8935
        {
 
8936
        error("Cannot parse arguments");
 
8937
        return false;
 
8938
        }
 
8939
 
 
8940
    buildtool::Make make;
 
8941
 
 
8942
    String target;
 
8943
 
 
8944
    //char *progName = argv[0];
 
8945
    for (int i=1 ; i<argc ; i++)
 
8946
        {
 
8947
        String arg = argv[i];
 
8948
        if (arg.size()>1 && arg[0]=='-')
 
8949
            {
 
8950
            if (arg == "-h" || arg == "-help")
 
8951
                {
 
8952
                usage(argc,argv);
 
8953
                return true;
 
8954
                }
 
8955
            else if (arg == "-version")
 
8956
                {
 
8957
                printf("%s", make.version().c_str());
 
8958
                return true;
 
8959
                }
 
8960
            else if (arg == "-f" || arg == "-file")
 
8961
                {
 
8962
                if (i>=argc)
 
8963
                   {
 
8964
                   usage(argc, argv);
 
8965
                   return false;
 
8966
                   }
 
8967
                i++; //eat option
 
8968
                make.setURI(argv[i]);
 
8969
                }
 
8970
            else if (arg.size()>2 && sequ(arg, "-D"))
 
8971
                {
 
8972
                String s = arg.substr(2, arg.size());
 
8973
                String name, value;
 
8974
                if (!parseProperty(s, name, value))
 
8975
                   {
 
8976
                   usage(argc, argv);
 
8977
                   return false;
 
8978
                   }
 
8979
                if (!make.specifyProperty(name, value))
 
8980
                    return false;
 
8981
                }
 
8982
            else
 
8983
                {
 
8984
                error("Unknown option:%s", arg.c_str());
 
8985
                return false;
 
8986
                }
 
8987
            }
 
8988
        else
 
8989
            {
 
8990
            if (target.size()>0)
 
8991
                {
 
8992
                error("only one initial target");
 
8993
                usage(argc, argv);
 
8994
                return false;
 
8995
                }
 
8996
            target = arg;
 
8997
            }
 
8998
        }
 
8999
 
 
9000
    //We have the options.  Now execute them
 
9001
    if (!make.run(target))
 
9002
        return false;
 
9003
 
 
9004
    return true;
 
9005
}
 
9006
 
 
9007
 
 
9008
 
 
9009
 
 
9010
/*
 
9011
static bool runMake()
 
9012
{
 
9013
    buildtool::Make make;
 
9014
    if (!make.run())
 
9015
        return false;
 
9016
    return true;
 
9017
}
 
9018
 
 
9019
 
 
9020
static bool pkgConfigTest()
 
9021
{
 
9022
    buildtool::PkgConfig pkgConfig;
 
9023
    if (!pkgConfig.readFile("gtk+-2.0.pc"))
 
9024
        return false;
 
9025
    return true;
 
9026
}
 
9027
 
 
9028
 
 
9029
 
 
9030
static bool depTest()
 
9031
{
 
9032
    buildtool::DepTool deptool;
 
9033
    deptool.setSourceDirectory("/dev/ink/inkscape/src");
 
9034
    if (!deptool.generateDependencies("build.dep"))
 
9035
        return false;
 
9036
    std::vector<buildtool::FileRec> res =
 
9037
           deptool.loadDepFile("build.dep");
 
9038
    if (res.size() == 0)
 
9039
        return false;
 
9040
    return true;
 
9041
}
 
9042
 
 
9043
static bool popenTest()
 
9044
{
 
9045
    buildtool::Make make;
 
9046
    buildtool::String out, err;
 
9047
    bool ret = make.executeCommand("gcc xx.cpp", "", out, err);
 
9048
    printf("Popen test:%d '%s' '%s'\n", ret, out.c_str(), err.c_str());
 
9049
    return true;
 
9050
}
 
9051
 
 
9052
 
 
9053
static bool propFileTest()
 
9054
{
 
9055
    buildtool::Make make;
 
9056
    make.parsePropertyFile("test.prop", "test.");
 
9057
    return true;
 
9058
}
 
9059
*/
 
9060
 
 
9061
int main(int argc, char **argv)
 
9062
{
 
9063
 
 
9064
    if (!parseOptions(argc, argv))
 
9065
        return 1;
 
9066
    /*
 
9067
    if (!popenTest())
 
9068
        return 1;
 
9069
 
 
9070
    if (!depTest())
 
9071
        return 1;
 
9072
    if (!propFileTest())
 
9073
        return 1;
 
9074
    if (runMake())
 
9075
        return 1;
 
9076
    */
 
9077
    return 0;
 
9078
}
 
9079
 
 
9080
 
 
9081
//########################################################################
 
9082
//# E N D 
 
9083
//########################################################################
 
9084
 
 
9085