~ubuntu-branches/debian/sid/itcl4/sid

« back to all changes in this revision

Viewing changes to win/nmakehlp.c

  • Committer: Package Import Robot
  • Author(s): Sergei Golovan
  • Date: 2018-03-06 11:36:54 UTC
  • Revision ID: package-import@ubuntu.com-20180306113654-w3oht8cjhtftrxby
Tags: upstream-4.1.1
ImportĀ upstreamĀ versionĀ 4.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ----------------------------------------------------------------------------
 
3
 * nmakehlp.c --
 
4
 *
 
5
 *      This is used to fix limitations within nmake and the environment.
 
6
 *
 
7
 * Copyright (c) 2002 by David Gravereaux.
 
8
 * Copyright (c) 2006 by Pat Thoyts
 
9
 *
 
10
 * See the file "license.terms" for information on usage and redistribution of
 
11
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
12
 * ----------------------------------------------------------------------------
 
13
 */
 
14
 
 
15
#define _CRT_SECURE_NO_DEPRECATE
 
16
#include <windows.h>
 
17
#define NO_SHLWAPI_GDI
 
18
#define NO_SHLWAPI_STREAM
 
19
#define NO_SHLWAPI_REG
 
20
#include <shlwapi.h>
 
21
#pragma comment (lib, "user32.lib")
 
22
#pragma comment (lib, "kernel32.lib")
 
23
#pragma comment (lib, "shlwapi.lib")
 
24
#include <stdio.h>
 
25
#include <math.h>
 
26
 
 
27
/*
 
28
 * This library is required for x64 builds with _some_ versions of MSVC
 
29
 */
 
30
#if defined(_M_IA64) || defined(_M_AMD64)
 
31
#if _MSC_VER >= 1400 && _MSC_VER < 1500
 
32
#pragma comment(lib, "bufferoverflowU")
 
33
#endif
 
34
#endif
 
35
 
 
36
/* ISO hack for dumb VC++ */
 
37
#ifdef _MSC_VER
 
38
#define   snprintf      _snprintf
 
39
#endif
 
40
 
 
41
 
 
42
/* protos */
 
43
 
 
44
static int CheckForCompilerFeature(const char *option);
 
45
static int CheckForLinkerFeature(const char **options, int count);
 
46
static int IsIn(const char *string, const char *substring);
 
47
static int SubstituteFile(const char *substs, const char *filename);
 
48
static int QualifyPath(const char *path);
 
49
static int LocateDependency(const char *keyfile);
 
50
static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
 
51
static DWORD WINAPI ReadFromPipe(LPVOID args);
 
52
 
 
53
/* globals */
 
54
 
 
55
#define CHUNK   25
 
56
#define STATICBUFFERSIZE    1000
 
57
typedef struct {
 
58
    HANDLE pipe;
 
59
    char buffer[STATICBUFFERSIZE];
 
60
} pipeinfo;
 
61
 
 
62
pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
 
63
pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};
 
64
 
 
65
/*
 
66
 * exitcodes: 0 == no, 1 == yes, 2 == error
 
67
 */
 
68
 
 
69
int
 
70
main(
 
71
    int argc,
 
72
    char *argv[])
 
73
{
 
74
    char msg[300];
 
75
    DWORD dwWritten;
 
76
    int chars;
 
77
    char *s;
 
78
 
 
79
    /*
 
80
     * Make sure children (cl.exe and link.exe) are kept quiet.
 
81
     */
 
82
 
 
83
    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
 
84
 
 
85
    /*
 
86
     * Make sure the compiler and linker aren't effected by the outside world.
 
87
     */
 
88
 
 
89
    SetEnvironmentVariable("CL", "");
 
90
    SetEnvironmentVariable("LINK", "");
 
91
 
 
92
    if (argc > 1 && *argv[1] == '-') {
 
93
        switch (*(argv[1]+1)) {
 
94
        case 'c':
 
95
            if (argc != 3) {
 
96
                chars = snprintf(msg, sizeof(msg) - 1,
 
97
                        "usage: %s -c <compiler option>\n"
 
98
                        "Tests for whether cl.exe supports an option\n"
 
99
                        "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
 
100
                WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
 
101
                        &dwWritten, NULL);
 
102
                return 2;
 
103
            }
 
104
            return CheckForCompilerFeature(argv[2]);
 
105
        case 'l':
 
106
            if (argc < 3) {
 
107
                chars = snprintf(msg, sizeof(msg) - 1,
 
108
                        "usage: %s -l <linker option> ?<mandatory option> ...?\n"
 
109
                        "Tests for whether link.exe supports an option\n"
 
110
                        "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
 
111
                WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
 
112
                        &dwWritten, NULL);
 
113
                return 2;
 
114
            }
 
115
            return CheckForLinkerFeature(&argv[2], argc-2);
 
116
        case 'f':
 
117
            if (argc == 2) {
 
118
                chars = snprintf(msg, sizeof(msg) - 1,
 
119
                        "usage: %s -f <string> <substring>\n"
 
120
                        "Find a substring within another\n"
 
121
                        "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
 
122
                WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
 
123
                        &dwWritten, NULL);
 
124
                return 2;
 
125
            } else if (argc == 3) {
 
126
                /*
 
127
                 * If the string is blank, there is no match.
 
128
                 */
 
129
 
 
130
                return 0;
 
131
            } else {
 
132
                return IsIn(argv[2], argv[3]);
 
133
            }
 
134
        case 's':
 
135
            if (argc == 2) {
 
136
                chars = snprintf(msg, sizeof(msg) - 1,
 
137
                        "usage: %s -s <substitutions file> <file>\n"
 
138
                        "Perform a set of string map type substutitions on a file\n"
 
139
                        "exitcodes: 0\n",
 
140
                        argv[0]);
 
141
                WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
 
142
                        &dwWritten, NULL);
 
143
                return 2;
 
144
            }
 
145
            return SubstituteFile(argv[2], argv[3]);
 
146
        case 'V':
 
147
            if (argc != 4) {
 
148
                chars = snprintf(msg, sizeof(msg) - 1,
 
149
                    "usage: %s -V filename matchstring\n"
 
150
                    "Extract a version from a file:\n"
 
151
                    "eg: pkgIndex.tcl \"package ifneeded http\"",
 
152
                    argv[0]);
 
153
                WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
 
154
                    &dwWritten, NULL);
 
155
                return 0;
 
156
            }
 
157
            s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
 
158
            if (s && *s) {
 
159
                printf("%s\n", s);
 
160
                return 0;
 
161
            } else
 
162
                return 1; /* Version not found. Return non-0 exit code */
 
163
 
 
164
        case 'Q':
 
165
            if (argc != 3) {
 
166
                chars = snprintf(msg, sizeof(msg) - 1,
 
167
                    "usage: %s -Q path\n"
 
168
                    "Emit the fully qualified path\n"
 
169
                    "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
 
170
                WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
 
171
                    &dwWritten, NULL);
 
172
                return 2;
 
173
            }
 
174
            return QualifyPath(argv[2]);
 
175
 
 
176
        case 'L':
 
177
            if (argc != 3) {
 
178
                chars = snprintf(msg, sizeof(msg) - 1,
 
179
                    "usage: %s -L keypath\n"
 
180
                    "Emit the fully qualified path of directory containing keypath\n"
 
181
                    "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
 
182
                WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
 
183
                    &dwWritten, NULL);
 
184
                return 2;
 
185
            }
 
186
            return LocateDependency(argv[2]);
 
187
        }
 
188
    }
 
189
    chars = snprintf(msg, sizeof(msg) - 1,
 
190
            "usage: %s -c|-f|-l|-Q|-s|-V ...\n"
 
191
            "This is a little helper app to equalize shell differences between WinNT and\n"
 
192
            "Win9x and get nmake.exe to accomplish its job.\n",
 
193
            argv[0]);
 
194
    WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
 
195
    return 2;
 
196
}
 
197
 
 
198
static int
 
199
CheckForCompilerFeature(
 
200
    const char *option)
 
201
{
 
202
    STARTUPINFO si;
 
203
    PROCESS_INFORMATION pi;
 
204
    SECURITY_ATTRIBUTES sa;
 
205
    DWORD threadID;
 
206
    char msg[300];
 
207
    BOOL ok;
 
208
    HANDLE hProcess, h, pipeThreads[2];
 
209
    char cmdline[100];
 
210
 
 
211
    hProcess = GetCurrentProcess();
 
212
 
 
213
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
 
214
    ZeroMemory(&si, sizeof(STARTUPINFO));
 
215
    si.cb = sizeof(STARTUPINFO);
 
216
    si.dwFlags   = STARTF_USESTDHANDLES;
 
217
    si.hStdInput = INVALID_HANDLE_VALUE;
 
218
 
 
219
    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
 
220
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
 
221
    sa.lpSecurityDescriptor = NULL;
 
222
    sa.bInheritHandle = FALSE;
 
223
 
 
224
    /*
 
225
     * Create a non-inheritible pipe.
 
226
     */
 
227
 
 
228
    CreatePipe(&Out.pipe, &h, &sa, 0);
 
229
 
 
230
    /*
 
231
     * Dupe the write side, make it inheritible, and close the original.
 
232
     */
 
233
 
 
234
    DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
 
235
            DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
 
236
 
 
237
    /*
 
238
     * Same as above, but for the error side.
 
239
     */
 
240
 
 
241
    CreatePipe(&Err.pipe, &h, &sa, 0);
 
242
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
 
243
            DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
 
244
 
 
245
    /*
 
246
     * Base command line.
 
247
     */
 
248
 
 
249
    lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");
 
250
 
 
251
    /*
 
252
     * Append our option for testing
 
253
     */
 
254
 
 
255
    lstrcat(cmdline, option);
 
256
 
 
257
    /*
 
258
     * Filename to compile, which exists, but is nothing and empty.
 
259
     */
 
260
 
 
261
    lstrcat(cmdline, " .\\nul");
 
262
 
 
263
    ok = CreateProcess(
 
264
            NULL,           /* Module name. */
 
265
            cmdline,        /* Command line. */
 
266
            NULL,           /* Process handle not inheritable. */
 
267
            NULL,           /* Thread handle not inheritable. */
 
268
            TRUE,           /* yes, inherit handles. */
 
269
            DETACHED_PROCESS, /* No console for you. */
 
270
            NULL,           /* Use parent's environment block. */
 
271
            NULL,           /* Use parent's starting directory. */
 
272
            &si,            /* Pointer to STARTUPINFO structure. */
 
273
            &pi);           /* Pointer to PROCESS_INFORMATION structure. */
 
274
 
 
275
    if (!ok) {
 
276
        DWORD err = GetLastError();
 
277
        int chars = snprintf(msg, sizeof(msg) - 1,
 
278
                "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
 
279
 
 
280
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
 
281
                FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
 
282
                (300-chars), 0);
 
283
        WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
 
284
        return 2;
 
285
    }
 
286
 
 
287
    /*
 
288
     * Close our references to the write handles that have now been inherited.
 
289
     */
 
290
 
 
291
    CloseHandle(si.hStdOutput);
 
292
    CloseHandle(si.hStdError);
 
293
 
 
294
    WaitForInputIdle(pi.hProcess, 5000);
 
295
    CloseHandle(pi.hThread);
 
296
 
 
297
    /*
 
298
     * Start the pipe reader threads.
 
299
     */
 
300
 
 
301
    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
 
302
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
 
303
 
 
304
    /*
 
305
     * Block waiting for the process to end.
 
306
     */
 
307
 
 
308
    WaitForSingleObject(pi.hProcess, INFINITE);
 
309
    CloseHandle(pi.hProcess);
 
310
 
 
311
    /*
 
312
     * Wait for our pipe to get done reading, should it be a little slow.
 
313
     */
 
314
 
 
315
    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
 
316
    CloseHandle(pipeThreads[0]);
 
317
    CloseHandle(pipeThreads[1]);
 
318
 
 
319
    /*
 
320
     * Look for the commandline warning code in both streams.
 
321
     *  - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
 
322
     */
 
323
 
 
324
    return !(strstr(Out.buffer, "D4002") != NULL
 
325
             || strstr(Err.buffer, "D4002") != NULL
 
326
             || strstr(Out.buffer, "D9002") != NULL
 
327
             || strstr(Err.buffer, "D9002") != NULL
 
328
             || strstr(Out.buffer, "D2021") != NULL
 
329
             || strstr(Err.buffer, "D2021") != NULL);
 
330
}
 
331
 
 
332
static int
 
333
CheckForLinkerFeature(
 
334
    const char **options,
 
335
    int count)
 
336
{
 
337
    STARTUPINFO si;
 
338
    PROCESS_INFORMATION pi;
 
339
    SECURITY_ATTRIBUTES sa;
 
340
    DWORD threadID;
 
341
    char msg[300];
 
342
    BOOL ok;
 
343
    HANDLE hProcess, h, pipeThreads[2];
 
344
    int i;
 
345
    char cmdline[255];
 
346
 
 
347
    hProcess = GetCurrentProcess();
 
348
 
 
349
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
 
350
    ZeroMemory(&si, sizeof(STARTUPINFO));
 
351
    si.cb = sizeof(STARTUPINFO);
 
352
    si.dwFlags   = STARTF_USESTDHANDLES;
 
353
    si.hStdInput = INVALID_HANDLE_VALUE;
 
354
 
 
355
    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
 
356
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
 
357
    sa.lpSecurityDescriptor = NULL;
 
358
    sa.bInheritHandle = TRUE;
 
359
 
 
360
    /*
 
361
     * Create a non-inheritible pipe.
 
362
     */
 
363
 
 
364
    CreatePipe(&Out.pipe, &h, &sa, 0);
 
365
 
 
366
    /*
 
367
     * Dupe the write side, make it inheritible, and close the original.
 
368
     */
 
369
 
 
370
    DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
 
371
            DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
 
372
 
 
373
    /*
 
374
     * Same as above, but for the error side.
 
375
     */
 
376
 
 
377
    CreatePipe(&Err.pipe, &h, &sa, 0);
 
378
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
 
379
            DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
 
380
 
 
381
    /*
 
382
     * Base command line.
 
383
     */
 
384
 
 
385
    lstrcpy(cmdline, "link.exe -nologo ");
 
386
 
 
387
    /*
 
388
     * Append our option for testing.
 
389
     */
 
390
 
 
391
    for (i = 0; i < count; i++) {
 
392
        lstrcat(cmdline, " \"");
 
393
        lstrcat(cmdline, options[i]);
 
394
        lstrcat(cmdline, "\"");
 
395
    }
 
396
 
 
397
    ok = CreateProcess(
 
398
            NULL,           /* Module name. */
 
399
            cmdline,        /* Command line. */
 
400
            NULL,           /* Process handle not inheritable. */
 
401
            NULL,           /* Thread handle not inheritable. */
 
402
            TRUE,           /* yes, inherit handles. */
 
403
            DETACHED_PROCESS, /* No console for you. */
 
404
            NULL,           /* Use parent's environment block. */
 
405
            NULL,           /* Use parent's starting directory. */
 
406
            &si,            /* Pointer to STARTUPINFO structure. */
 
407
            &pi);           /* Pointer to PROCESS_INFORMATION structure. */
 
408
 
 
409
    if (!ok) {
 
410
        DWORD err = GetLastError();
 
411
        int chars = snprintf(msg, sizeof(msg) - 1,
 
412
                "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
 
413
 
 
414
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
 
415
                FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
 
416
                (300-chars), 0);
 
417
        WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
 
418
        return 2;
 
419
    }
 
420
 
 
421
    /*
 
422
     * Close our references to the write handles that have now been inherited.
 
423
     */
 
424
 
 
425
    CloseHandle(si.hStdOutput);
 
426
    CloseHandle(si.hStdError);
 
427
 
 
428
    WaitForInputIdle(pi.hProcess, 5000);
 
429
    CloseHandle(pi.hThread);
 
430
 
 
431
    /*
 
432
     * Start the pipe reader threads.
 
433
     */
 
434
 
 
435
    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
 
436
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
 
437
 
 
438
    /*
 
439
     * Block waiting for the process to end.
 
440
     */
 
441
 
 
442
    WaitForSingleObject(pi.hProcess, INFINITE);
 
443
    CloseHandle(pi.hProcess);
 
444
 
 
445
    /*
 
446
     * Wait for our pipe to get done reading, should it be a little slow.
 
447
     */
 
448
 
 
449
    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
 
450
    CloseHandle(pipeThreads[0]);
 
451
    CloseHandle(pipeThreads[1]);
 
452
 
 
453
    /*
 
454
     * Look for the commandline warning code in the stderr stream.
 
455
     */
 
456
 
 
457
    return !(strstr(Out.buffer, "LNK1117") != NULL ||
 
458
            strstr(Err.buffer, "LNK1117") != NULL ||
 
459
            strstr(Out.buffer, "LNK4044") != NULL ||
 
460
            strstr(Err.buffer, "LNK4044") != NULL ||
 
461
            strstr(Out.buffer, "LNK4224") != NULL ||
 
462
            strstr(Err.buffer, "LNK4224") != NULL);
 
463
}
 
464
 
 
465
static DWORD WINAPI
 
466
ReadFromPipe(
 
467
    LPVOID args)
 
468
{
 
469
    pipeinfo *pi = (pipeinfo *) args;
 
470
    char *lastBuf = pi->buffer;
 
471
    DWORD dwRead;
 
472
    BOOL ok;
 
473
 
 
474
  again:
 
475
    if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
 
476
        CloseHandle(pi->pipe);
 
477
        return (DWORD)-1;
 
478
    }
 
479
    ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
 
480
    if (!ok || dwRead == 0) {
 
481
        CloseHandle(pi->pipe);
 
482
        return 0;
 
483
    }
 
484
    lastBuf += dwRead;
 
485
    goto again;
 
486
 
 
487
    return 0;  /* makes the compiler happy */
 
488
}
 
489
 
 
490
static int
 
491
IsIn(
 
492
    const char *string,
 
493
    const char *substring)
 
494
{
 
495
    return (strstr(string, substring) != NULL);
 
496
}
 
497
 
 
498
/*
 
499
 * GetVersionFromFile --
 
500
 *      Looks for a match string in a file and then returns the version
 
501
 *      following the match where a version is anything acceptable to
 
502
 *      package provide or package ifneeded.
 
503
 */
 
504
 
 
505
static const char *
 
506
GetVersionFromFile(
 
507
    const char *filename,
 
508
    const char *match,
 
509
    int numdots)
 
510
{
 
511
    size_t cbBuffer = 100;
 
512
    static char szBuffer[100];
 
513
    char *szResult = NULL;
 
514
    FILE *fp = fopen(filename, "rt");
 
515
 
 
516
    if (fp != NULL) {
 
517
        /*
 
518
         * Read data until we see our match string.
 
519
         */
 
520
 
 
521
        while (fgets(szBuffer, cbBuffer, fp) != NULL) {
 
522
            LPSTR p, q;
 
523
 
 
524
            p = strstr(szBuffer, match);
 
525
            if (p != NULL) {
 
526
                /*
 
527
                 * Skip to first digit after the match.
 
528
                 */
 
529
 
 
530
                p += strlen(match);
 
531
                while (*p && !isdigit(*p)) {
 
532
                    ++p;
 
533
                }
 
534
 
 
535
                /*
 
536
                 * Find ending whitespace.
 
537
                 */
 
538
 
 
539
                q = p;
 
540
                while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q)
 
541
                            && (!strchr("ab", q[-1])) || --numdots))) {
 
542
                    ++q;
 
543
                }
 
544
 
 
545
                memcpy(szBuffer, p, q - p);
 
546
                szBuffer[q-p] = 0;
 
547
                szResult = szBuffer;
 
548
                break;
 
549
            }
 
550
        }
 
551
        fclose(fp);
 
552
    }
 
553
    return szResult;
 
554
}
 
555
 
 
556
/*
 
557
 * List helpers for the SubstituteFile function
 
558
 */
 
559
 
 
560
typedef struct list_item_t {
 
561
    struct list_item_t *nextPtr;
 
562
    char * key;
 
563
    char * value;
 
564
} list_item_t;
 
565
 
 
566
/* insert a list item into the list (list may be null) */
 
567
static list_item_t *
 
568
list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
 
569
{
 
570
    list_item_t *itemPtr = malloc(sizeof(list_item_t));
 
571
    if (itemPtr) {
 
572
        itemPtr->key = strdup(key);
 
573
        itemPtr->value = strdup(value);
 
574
        itemPtr->nextPtr = NULL;
 
575
 
 
576
        while(*listPtrPtr) {
 
577
            listPtrPtr = &(*listPtrPtr)->nextPtr;
 
578
        }
 
579
        *listPtrPtr = itemPtr;
 
580
    }
 
581
    return itemPtr;
 
582
}
 
583
 
 
584
static void
 
585
list_free(list_item_t **listPtrPtr)
 
586
{
 
587
    list_item_t *tmpPtr, *listPtr = *listPtrPtr;
 
588
    while (listPtr) {
 
589
        tmpPtr = listPtr;
 
590
        listPtr = listPtr->nextPtr;
 
591
        free(tmpPtr->key);
 
592
        free(tmpPtr->value);
 
593
        free(tmpPtr);
 
594
    }
 
595
}
 
596
 
 
597
/*
 
598
 * SubstituteFile --
 
599
 *      As windows doesn't provide anything useful like sed and it's unreliable
 
600
 *      to use the tclsh you are building against (consider x-platform builds -
 
601
 *      eg compiling AMD64 target from IX86) we provide a simple substitution
 
602
 *      option here to handle autoconf style substitutions.
 
603
 *      The substitution file is whitespace and line delimited. The file should
 
604
 *      consist of lines matching the regular expression:
 
605
 *        \s*\S+\s+\S*$
 
606
 *
 
607
 *      Usage is something like:
 
608
 *        nmakehlp -S << $** > $@
 
609
 *        @PACKAGE_NAME@ $(PACKAGE_NAME)
 
610
 *        @PACKAGE_VERSION@ $(PACKAGE_VERSION)
 
611
 *        <<
 
612
 */
 
613
 
 
614
static int
 
615
SubstituteFile(
 
616
    const char *substitutions,
 
617
    const char *filename)
 
618
{
 
619
    size_t cbBuffer = 1024;
 
620
    static char szBuffer[1024], szCopy[1024];
 
621
    char *szResult = NULL;
 
622
    list_item_t *substPtr = NULL;
 
623
    FILE *fp, *sp;
 
624
 
 
625
    fp = fopen(filename, "rt");
 
626
    if (fp != NULL) {
 
627
 
 
628
        /*
 
629
         * Build a list of substutitions from the first filename
 
630
         */
 
631
 
 
632
        sp = fopen(substitutions, "rt");
 
633
        if (sp != NULL) {
 
634
            while (fgets(szBuffer, cbBuffer, sp) != NULL) {
 
635
                unsigned char *ks, *ke, *vs, *ve;
 
636
                ks = (unsigned char*)szBuffer;
 
637
                while (ks && *ks && isspace(*ks)) ++ks;
 
638
                ke = ks;
 
639
                while (ke && *ke && !isspace(*ke)) ++ke;
 
640
                vs = ke;
 
641
                while (vs && *vs && isspace(*vs)) ++vs;
 
642
                ve = vs;
 
643
                while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
 
644
                *ke = 0, *ve = 0;
 
645
                list_insert(&substPtr, (char*)ks, (char*)vs);
 
646
            }
 
647
            fclose(sp);
 
648
        }
 
649
 
 
650
        /* debug: dump the list */
 
651
#ifdef _DEBUG
 
652
        {
 
653
            int n = 0;
 
654
            list_item_t *p = NULL;
 
655
            for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
 
656
                fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
 
657
            }
 
658
        }
 
659
#endif
 
660
 
 
661
        /*
 
662
         * Run the substitutions over each line of the input
 
663
         */
 
664
 
 
665
        while (fgets(szBuffer, cbBuffer, fp) != NULL) {
 
666
            list_item_t *p = NULL;
 
667
            for (p = substPtr; p != NULL; p = p->nextPtr) {
 
668
                char *m = strstr(szBuffer, p->key);
 
669
                if (m) {
 
670
                    char *cp, *op, *sp;
 
671
                    cp = szCopy;
 
672
                    op = szBuffer;
 
673
                    while (op != m) *cp++ = *op++;
 
674
                    sp = p->value;
 
675
                    while (sp && *sp) *cp++ = *sp++;
 
676
                    op += strlen(p->key);
 
677
                    while (*op) *cp++ = *op++;
 
678
                    *cp = 0;
 
679
                    memcpy(szBuffer, szCopy, sizeof(szCopy));
 
680
                }
 
681
            }
 
682
            printf(szBuffer);
 
683
        }
 
684
 
 
685
        list_free(&substPtr);
 
686
    }
 
687
    fclose(fp);
 
688
    return 0;
 
689
}
 
690
 
 
691
/*
 
692
 * QualifyPath --
 
693
 *
 
694
 *      This composes the current working directory with a provided path
 
695
 *      and returns the fully qualified and normalized path.
 
696
 *      Mostly needed to setup paths for testing.
 
697
 */
 
698
 
 
699
static int
 
700
QualifyPath(
 
701
    const char *szPath)
 
702
{
 
703
    char szCwd[MAX_PATH + 1];
 
704
    char szTmp[MAX_PATH + 1];
 
705
    char *p;
 
706
    GetCurrentDirectory(MAX_PATH, szCwd);
 
707
    while ((p = strchr(szPath, '/')) && *p)
 
708
        *p = '\\';
 
709
    PathCombine(szTmp, szCwd, szPath);
 
710
    PathCanonicalize(szCwd, szTmp);
 
711
    printf("%s\n", szCwd);
 
712
    return 0;
 
713
}
 
714
 
 
715
/*
 
716
 * Implements LocateDependency for a single directory. See that command
 
717
 * for an explanation.
 
718
 * Returns 0 if found after printing the directory.
 
719
 * Returns 1 if not found but no errors.
 
720
 * Returns 2 on any kind of error
 
721
 * Basically, these are used as exit codes for the process.
 
722
 */
 
723
static int LocateDependencyHelper(const char *dir, const char *keypath)
 
724
{
 
725
    HANDLE hSearch;
 
726
    char path[MAX_PATH+1];
 
727
    int dirlen, keylen, ret;
 
728
    WIN32_FIND_DATA finfo;
 
729
 
 
730
    if (dir == NULL || keypath == NULL)
 
731
        return 2; /* Have no real error reporting mechanism into nmake */
 
732
    dirlen = strlen(dir);
 
733
    if ((dirlen + 3) > sizeof(path))
 
734
        return 2;
 
735
    strncpy(path, dir, dirlen);
 
736
    strncpy(path+dirlen, "\\*", 3);     /* Including terminating \0 */
 
737
    keylen = strlen(keypath);
 
738
 
 
739
#if 0 /* This function is not available in Visual C++ 6 */
 
740
    /*
 
741
     * Use numerics 0 -> FindExInfoStandard,
 
742
     * 1 -> FindExSearchLimitToDirectories, 
 
743
     * as these are not defined in Visual C++ 6
 
744
     */
 
745
    hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
 
746
#else
 
747
    hSearch = FindFirstFile(path, &finfo);
 
748
#endif
 
749
    if (hSearch == INVALID_HANDLE_VALUE)
 
750
        return 1; /* Not found */
 
751
 
 
752
    /* Loop through all subdirs checking if the keypath is under there */
 
753
    ret = 1; /* Assume not found */
 
754
    do {
 
755
        int sublen;
 
756
        /*
 
757
         * We need to check it is a directory despite the 
 
758
         * FindExSearchLimitToDirectories in the above call. See SDK docs
 
759
         */
 
760
        if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
 
761
            continue;
 
762
        sublen = strlen(finfo.cFileName);
 
763
        if ((dirlen+1+sublen+1+keylen+1) > sizeof(path))
 
764
            continue;           /* Path does not fit, assume not matched */
 
765
        strncpy(path+dirlen+1, finfo.cFileName, sublen);
 
766
        path[dirlen+1+sublen] = '\\';
 
767
        strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
 
768
        if (PathFileExists(path)) {
 
769
            /* Found a match, print to stdout */
 
770
            path[dirlen+1+sublen] = '\0';
 
771
            QualifyPath(path);
 
772
            ret = 0;
 
773
            break;
 
774
        }
 
775
    } while (FindNextFile(hSearch, &finfo));
 
776
    FindClose(hSearch);
 
777
    return ret;
 
778
}
 
779
 
 
780
/*
 
781
 * LocateDependency --
 
782
 *
 
783
 *      Locates a dependency for a package.
 
784
 *        keypath - a relative path within the package directory
 
785
 *          that is used to confirm it is the correct directory.
 
786
 *      The search path for the package directory is currently only
 
787
 *      the parent and grandparent of the current working directory.
 
788
 *      If found, the command prints 
 
789
 *         name_DIRPATH=<full path of located directory>
 
790
 *      and returns 0. If not found, does not print anything and returns 1.
 
791
 */
 
792
static int LocateDependency(const char *keypath)
 
793
{
 
794
    int i, ret;
 
795
    static char *paths[] = {"..", "..\\..", "..\\..\\.."};
 
796
    
 
797
    for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
 
798
        ret = LocateDependencyHelper(paths[i], keypath);
 
799
        if (ret == 0)
 
800
            return ret;
 
801
    }
 
802
    return ret;
 
803
}
 
804
 
 
805
 
 
806
/*
 
807
 * Local variables:
 
808
 *   mode: c
 
809
 *   c-basic-offset: 4
 
810
 *   fill-column: 78
 
811
 *   indent-tabs-mode: t
 
812
 *   tab-width: 8
 
813
 * End:
 
814
 */