~inkscape.dev/inkscape/trunk

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