Itk - the [incr Tk] extension

Check-in [1b12c5b8dc]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dgp-method-type
Files: files | file ages | folders
SHA1: 1b12c5b8dc5d1778e52ef0bb6a57313bf6ebd2b0
User & Date: dgp 2016-09-16 15:16:29
Context
2016-09-19
19:01
merge trunk check-in: 360f468ec5 user: dgp tags: dgp-method-type
2016-09-16
15:16
merge trunk check-in: 1b12c5b8dc user: dgp tags: dgp-method-type
15:10
Improvements to the MSVC build machinery and porting fixes to code from Ashok Nadkarni. check-in: 3f30d567bc user: dgp tags: trunk
2016-03-01
15:44
merge trunk check-in: db8e1aec88 user: dgp tags: dgp-method-type
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/itk.h.

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#ifndef TCL_FINAL_RELEASE
#   define TCL_FINAL_RELEASE	2
#endif


#define ITK_MAJOR_VERSION	4
#define ITK_MINOR_VERSION	0
#define ITK_RELEASE_LEVEL	TCL_RELEASE
#define ITK_RELEASE_SERIAL	2

#define ITK_VERSION		"4.0"
#define ITK_PATCH_LEVEL		"4.0.2"


/*






|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#ifndef TCL_FINAL_RELEASE
#   define TCL_FINAL_RELEASE	2
#endif


#define ITK_MAJOR_VERSION	4
#define ITK_MINOR_VERSION	0
#define ITK_RELEASE_LEVEL	TCL_FINAL_RELEASE
#define ITK_RELEASE_SERIAL	2

#define ITK_VERSION		"4.0"
#define ITK_PATCH_LEVEL		"4.0.2"


/*

Changes to generic/itkArchBase.c.

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
...
199
200
201
202
203
204
205

206
207
208
209
210
211
212
...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
....
1666
1667
1668
1669
1670
1671
1672
1673

1674
1675
1676
1677
1678
1679
1680
1681
1682
    ArchMergeInfo *mergeInfo = NULL;
    Tcl_Obj *objNamePtr = NULL;
    Tcl_Obj *tmpNamePtr = NULL;
    Tcl_Obj *winNamePtr = NULL;
    Tcl_Obj *hullNamePtr = NULL;
    int pLevel = ITCL_PUBLIC;

    ItclShowArgs(1, "Itk_ArchCompAddCmd", objc, objv);
    int newEntry;
    int result;
    CONST char *cmd;
    CONST char *token;
    CONST char *resultStr;
    char *name;
    Tcl_Namespace *parserNs;
................................................................................
    Tcl_CallFrame frame;
    Tcl_CallFrame *uplevelFramePtr;
    Tcl_CallFrame *oldFramePtr = NULL;
    ItclObjectInfo *infoPtr;
    ItclCallContext *callContextPtr;
#endif


    /*
     *  Get the Archetype info associated with this widget.
     */
    contextClass = NULL;
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
        !contextObj) {

................................................................................


    /*
     *  Create the component record.  Set the protection level
     *  according to the "-protected" or "-private" option.
     */
    ownerClass = contextClass;
#if 0
    Tcl_Namespace *ownerNsPtr;
    callContextPtr = Itcl_PeekStack(&infoPtr->contextStack);
    ownerNsPtr = callContextPtr->nsPtr;
    if (ownerNsPtr != NULL) {
        Tcl_HashEntry *hPtr;
	int idx = 2;
	if (Itcl_GetStackSize(&infoPtr->contextStack) == 1) {
	   idx = 1;
	}
        callContextPtr = Itcl_GetStackValue(&infoPtr->contextStack,
	        Itcl_GetStackSize(&infoPtr->contextStack)-idx);
        hPtr = Tcl_FindHashEntry(&infoPtr->namespaceClasses,
                (char *)callContextPtr->nsPtr);
        ownerClass = (ItclClass*)Tcl_GetHashValue(hPtr);
    }
#endif

    archComp = Itk_CreateArchComponent(interp, info, name, ownerClass,
            accessCmd);

    if (!archComp) {
        goto compFail;
    }
................................................................................
     *  If this variable has some "config" code, invoke it now.
     *
     *  NOTE:  Invoke the "config" code in the class scope
     *    containing the data member.
     */
    mcode = ivPtr->codePtr;
    if (mcode && mcode->bodyPtr) {


        Itcl_SetCallFrameResolver(interp, ivPtr->iclsPtr->resolvePtr);
        Tcl_Namespace *saveNsPtr = Tcl_GetCurrentNamespace(interp);
        Itcl_SetCallFrameNamespace(interp, ivPtr->iclsPtr->nsPtr);
        result = Tcl_EvalObjEx(interp, mcode->bodyPtr, 0);
        Itcl_SetCallFrameNamespace(interp, saveNsPtr);

        if (result == TCL_OK) {
            Tcl_ResetResult(interp);
        } else {






<







 







>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
>

|







176
177
178
179
180
181
182

183
184
185
186
187
188
189
...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
353
354
355
356
357
358
359

















360
361
362
363
364
365
366
....
1649
1650
1651
1652
1653
1654
1655

1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
    ArchMergeInfo *mergeInfo = NULL;
    Tcl_Obj *objNamePtr = NULL;
    Tcl_Obj *tmpNamePtr = NULL;
    Tcl_Obj *winNamePtr = NULL;
    Tcl_Obj *hullNamePtr = NULL;
    int pLevel = ITCL_PUBLIC;


    int newEntry;
    int result;
    CONST char *cmd;
    CONST char *token;
    CONST char *resultStr;
    char *name;
    Tcl_Namespace *parserNs;
................................................................................
    Tcl_CallFrame frame;
    Tcl_CallFrame *uplevelFramePtr;
    Tcl_CallFrame *oldFramePtr = NULL;
    ItclObjectInfo *infoPtr;
    ItclCallContext *callContextPtr;
#endif

    ItclShowArgs(1, "Itk_ArchCompAddCmd", objc, objv);
    /*
     *  Get the Archetype info associated with this widget.
     */
    contextClass = NULL;
    if (Itcl_GetContext(interp, &contextClass, &contextObj) != TCL_OK ||
        !contextObj) {

................................................................................


    /*
     *  Create the component record.  Set the protection level
     *  according to the "-protected" or "-private" option.
     */
    ownerClass = contextClass;


















    archComp = Itk_CreateArchComponent(interp, info, name, ownerClass,
            accessCmd);

    if (!archComp) {
        goto compFail;
    }
................................................................................
     *  If this variable has some "config" code, invoke it now.
     *
     *  NOTE:  Invoke the "config" code in the class scope
     *    containing the data member.
     */
    mcode = ivPtr->codePtr;
    if (mcode && mcode->bodyPtr) {

        Tcl_Namespace *saveNsPtr;
        Itcl_SetCallFrameResolver(interp, ivPtr->iclsPtr->resolvePtr);
        saveNsPtr = Tcl_GetCurrentNamespace(interp);
        Itcl_SetCallFrameNamespace(interp, ivPtr->iclsPtr->nsPtr);
        result = Tcl_EvalObjEx(interp, mcode->bodyPtr, 0);
        Itcl_SetCallFrameNamespace(interp, saveNsPtr);

        if (result == TCL_OK) {
            Tcl_ResetResult(interp);
        } else {

Changes to generic/itkArchetype.c.

257
258
259
260
261
262
263

264
265
266
267
268
269
270
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
407
408
409
410
411
412
413



414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
...
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
    int newEntry;
    int result;
    ArchInfo *info;
    ItclClass *contextClass;
    ItclObject *contextObj;
    Tcl_HashTable *objsWithArchInfo;
    Tcl_HashEntry *entry;


    ItclShowArgs(2, "Itk_ArchInitOptsCmd", objc, objv);
    if (objc != 1) {
        Tcl_WrongNumArgs(interp, 1, objv, "");
        return TCL_ERROR;
    }

................................................................................
    /*
     *  Make sure that the access command for this object
     *  resides in the global namespace.  If need be, move
     *  the command.
     */
    result = TCL_OK;

    Tcl_CmdInfo cmdInfo;
    Tcl_GetCommandInfoFromToken(contextObj->accessCmd, &cmdInfo);
    if (cmdInfo.namespacePtr != Tcl_GetGlobalNamespace(interp)) {
        Tcl_Obj *oldNamePtr, *newNamePtr;

        oldNamePtr = Tcl_NewStringObj((char*)NULL, 0);
        Tcl_GetCommandFullName(interp, contextObj->accessCmd, oldNamePtr);
        Tcl_IncrRefCount(oldNamePtr);
................................................................................
    int objc,                /* number of arguments */
    Tcl_Obj *CONST objv[])   /* argument objects */
{
    char *cmd;
    char *token;
    char c;
    int length;




    ItclShowArgs(2, "Itk_ArchComponentCmd", objc, objv);
    /*
     *  Check arguments and handle the various options...
     */
    Tcl_DString buffer;
    const char *head;
    const char *tail;
    cmd = Tcl_GetString(objv[0]);
    Itcl_ParseNamespPath(cmd, &buffer, &head, &tail);
    if (objc < 2) {
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
            "wrong # args: should be one of...\n",
            "  ", tail, " add ?-protected? ?-private? ?--? name createCmds ?optionCmds?\n",
            "  ", tail, " delete name ?name name...?",
................................................................................
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
        return TCL_ERROR;
    }

callingNs = Tcl_GetCurrentNamespace(interp);

#if 0
    ItclObjectInfo *infoPtr;
    infoPtr = (ItclObjectInfo *)Tcl_GetAssocData(interp,
            ITCL_INTERP_DATA, NULL);
    if (Itcl_GetStackSize(&infoPtr->contextStack) == 1) {
        callingNs = Tcl_GetGlobalNamespace(interp);
    } else {
	ItclCallContext *callContextPtr;
	callContextPtr = Itcl_GetStackValue(&infoPtr->contextStack,






>







 







<







 







>
>
>





<
<
<







 







<







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
...
303
304
305
306
307
308
309

310
311
312
313
314
315
316
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421



422
423
424
425
426
427
428
...
891
892
893
894
895
896
897

898
899
900
901
902
903
904
    int newEntry;
    int result;
    ArchInfo *info;
    ItclClass *contextClass;
    ItclObject *contextObj;
    Tcl_HashTable *objsWithArchInfo;
    Tcl_HashEntry *entry;
    Tcl_CmdInfo cmdInfo;

    ItclShowArgs(2, "Itk_ArchInitOptsCmd", objc, objv);
    if (objc != 1) {
        Tcl_WrongNumArgs(interp, 1, objv, "");
        return TCL_ERROR;
    }

................................................................................
    /*
     *  Make sure that the access command for this object
     *  resides in the global namespace.  If need be, move
     *  the command.
     */
    result = TCL_OK;


    Tcl_GetCommandInfoFromToken(contextObj->accessCmd, &cmdInfo);
    if (cmdInfo.namespacePtr != Tcl_GetGlobalNamespace(interp)) {
        Tcl_Obj *oldNamePtr, *newNamePtr;

        oldNamePtr = Tcl_NewStringObj((char*)NULL, 0);
        Tcl_GetCommandFullName(interp, contextObj->accessCmd, oldNamePtr);
        Tcl_IncrRefCount(oldNamePtr);
................................................................................
    int objc,                /* number of arguments */
    Tcl_Obj *CONST objv[])   /* argument objects */
{
    char *cmd;
    char *token;
    char c;
    int length;
    Tcl_DString buffer;
    const char *head;
    const char *tail;

    ItclShowArgs(2, "Itk_ArchComponentCmd", objc, objv);
    /*
     *  Check arguments and handle the various options...
     */



    cmd = Tcl_GetString(objv[0]);
    Itcl_ParseNamespPath(cmd, &buffer, &head, &tail);
    if (objc < 2) {
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
            "wrong # args: should be one of...\n",
            "  ", tail, " add ?-protected? ?-private? ?--? name createCmds ?optionCmds?\n",
            "  ", tail, " delete name ?name name...?",
................................................................................
    if (Itk_GetArchInfo(interp, contextObj, &info) != TCL_OK) {
        return TCL_ERROR;
    }

callingNs = Tcl_GetCurrentNamespace(interp);

#if 0

    infoPtr = (ItclObjectInfo *)Tcl_GetAssocData(interp,
            ITCL_INTERP_DATA, NULL);
    if (Itcl_GetStackSize(&infoPtr->contextStack) == 1) {
        callingNs = Tcl_GetGlobalNamespace(interp);
    } else {
	ItclCallContext *callContextPtr;
	callContextPtr = Itcl_GetStackValue(&infoPtr->contextStack,

Changes to generic/itkOption.c.

220
221
222
223
224
225
226

227
228
229
230
231
232
233
234
235
236
    /*
     *  If the option has any config code, execute it now.
     *  Make sure that the namespace context is set up correctly.
     */
    mcode = opt->codePtr;
    if (mcode && mcode->bodyPtr) {

//fprintf(stderr, "EXE!%s!\n", Tcl_GetString(mcode->bodyPtr));
        Itcl_SetCallFrameResolver(interp, opt->iclsPtr->resolvePtr);
        Tcl_Namespace *saveNsPtr = Tcl_GetCurrentNamespace(interp);
//fprintf(stderr, "MCNS!%s!\n", saveNsPtr->fullName);
        Itcl_SetCallFrameNamespace(interp, opt->iclsPtr->nsPtr);
        result = Tcl_EvalObjEx(interp, mcode->bodyPtr, 0);
        Itcl_SetCallFrameNamespace(interp, saveNsPtr);
#ifdef NOTDEF
        result = Itcl_EvalMemberCode(interp, (ItclMemberFunc*)NULL,
            opt->member, contextObj, 0, (Tcl_Obj**)NULL);






>


|







220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    /*
     *  If the option has any config code, execute it now.
     *  Make sure that the namespace context is set up correctly.
     */
    mcode = opt->codePtr;
    if (mcode && mcode->bodyPtr) {
        Tcl_Namespace *saveNsPtr;
//fprintf(stderr, "EXE!%s!\n", Tcl_GetString(mcode->bodyPtr));
        Itcl_SetCallFrameResolver(interp, opt->iclsPtr->resolvePtr);
        saveNsPtr = Tcl_GetCurrentNamespace(interp);
//fprintf(stderr, "MCNS!%s!\n", saveNsPtr->fullName);
        Itcl_SetCallFrameNamespace(interp, opt->iclsPtr->nsPtr);
        result = Tcl_EvalObjEx(interp, mcode->bodyPtr, 0);
        Itcl_SetCallFrameNamespace(interp, saveNsPtr);
#ifdef NOTDEF
        result = Itcl_EvalMemberCode(interp, (ItclMemberFunc*)NULL,
            opt->member, contextObj, 0, (Tcl_Obj**)NULL);

Changes to win/makefile.vc.

1
2
3
4
5
6
7
8
9
10


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115


116
117

118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
...
169
170
171
172
173
174
175









176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206







207
208
209
210
211
212
213
...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
#------------------------------------------------------------------------------
# Visual C++ 5.0+ makefile for [Incr Tk]
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 1993-1998 Lucent Technologies, Inc.
#------------------------------------------------------------------------------
#  Do not modify this file!
#------------------------------------------------------------------------------



!if !exist("makefile.vc")
MSG = ^
You must run this makefile only from the directory it is in.^
Please `cd` to its location first.
!error $(MSG) 
!endif

PROJECT	= itk
!include "..\..\rules.vc"


!if $(TCLINSTALL)
!message *** Warning: [Incr Tk] requires the source distribution of Tcl to build from,
!message ***    at this time, sorry.  Please set the TCLDIR and TKDIR macros to point
!message ***    to the sources.
!endif

ITCLDIR		= ..\..\itcl


!if [nmakehlp -g $(ITCLDIR)\generic\itcl.h ITCL_VERSION] == 33
ITCL_DOTVERSION	= 3.3
!elseif [nmakehlp -g $(ITCLDIR)\generic\itcl.h ITCL_VERSION] == 34
ITCL_DOTVERSION	= 3.4
!elseif [nmakehlp -g $(ITCLDIR)\generic\itcl.h ITCL_VERSION] == 35
ITCL_DOTVERSION	= 3.5
!elseif [nmakehlp -g $(ITCLDIR)\generic\itcl.h ITCL_VERSION] == 0
MSG =^
Can't get version string from ..\generic\itcl.h
!error $(MSG)
!endif
ITCL_VERSION	= $(ITCL_DOTVERSION:.=)

!if [nmakehlp -g ..\generic\itk.h ITK_VERSION] == 33
ITK_DOTVERSION	= 3.3
!elseif [nmakehlp -g ..\generic\itk.h ITK_VERSION] == 34
ITK_DOTVERSION	= 3.4
!elseif [nmakehlp -g ..\generic\itk.h ITK_VERSION] == 35
ITK_DOTVERSION	= 3.5
!elseif [nmakehlp -g ..\generic\itk.h ITK_VERSION] == 0
MSG =^
Can't get version string from ..\generic\itk.h
!error $(MSG)
!endif
ITK_VERSION	= $(ITK_DOTVERSION:.=)


BINROOT		= .
ROOT		= ..
STUBPREFIX	= $(PROJECT)stub

PKGINDEX	= "$(TMP_DIR)\pkgIndex.tcl"

ITCLLIBNAME	= itcl$(ITCL_VERSION)$(SUFX).$(EXT)
ITCLLIB		= "$(ITCLDIR)\win\$(OUT_DIR)\$(ITCLLIBNAME)"
ITKIMPLIB	= "$(OUT_DIR)\$(PROJECT)$(ITK_VERSION)$(SUFX).lib"
ITKSTUBLIBNAME	= $(STUBPREFIX)$(ITK_VERSION).lib
ITKSTUBLIB	= "$(OUT_DIR)\$(ITKSTUBLIBNAME)"

!if $(TCL_DOES_STUBS)
ITKLIBNAME	= $(PROJECT)$(ITK_VERSION)$(SUFX).$(EXT)
ITCLIMPLIBNAME	= itcl$(ITCL_VERSION)$(SUFX).$(EXT)
!else
ITKLIBNAME	= $(PROJECT)$(ITK_VERSION)80$(SUFX).$(EXT)
ITCLIMPLIBNAME	= itcl$(ITCL_VERSION)80$(SUFX).lib
!endif
ITKLIB		= "$(OUT_DIR)\$(ITKLIBNAME)"
ITCLIMPLIB	= "$(ITCLDIR)\win\Release\$(ITCLIMPLIBNAME)"


!if $(TCLINSTALL)
TKSTUBLIB	= "$(TCLDIR)\lib\tkstub$(TCL_VERSION).lib"
TKIMPLIB	= "$(TCLDIR)\lib\tk$(TCL_VERSION)$(DBGX).lib"
WISH		= "$(TCLDIR)\bin\wish$(TCL_VERSION)$(DBGX).exe"
TCL_LIBRARY	= 
TK_LIBRARY	= 
!else
TKSTUBLIB	= "$(TKDIR)\win\Release\tkstub$(TCL_VERSION).lib"
TKIMPLIB	= "$(TKDIR)\win\$(OUT_DIR)\tk$(TCL_VERSION)$(DBGX).lib"
WISH		= "$(TKDIR)\win\$(OUT_DIR)\wish$(TCL_VERSION)$(DBGX).exe"
TCL_LIBRARY	= "$(TCLDIR)\library"
TK_LIBRARY	= "$(TKDIR)\library"
!endif
ITCL_LIBRARY	= "$(ITCLDIR:\=/)/library"
ITK_LIBRARY	= "$(ROOT)/library

ITCLSTUBLIBNAME	= itclstub$(ITCL_VERSION).lib
ITCLSTUBLIB	= "$(ITCLDIR)\win\Release\$(ITCLSTUBLIBNAME)"

### For Tcl 8.0
!if !$(TCL_DOES_STUBS)
TCLSTUBLIB	= $(TCLIMPLIB)
TKSTUBLIB	= $(TKIMPLIB)
ITCLSTUBLIB	= $(ITCLIMPLIB)
!endif


BIN_INSTALL_DIR		= $(_INSTALLDIR)\bin
DOC_INSTALL_DIR		= $(_INSTALLDIR)\doc
LIB_INSTALL_DIR		= $(_INSTALLDIR)\lib
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\lib\itk$(ITK_DOTVERSION)
INCLUDE_INSTALL_DIR	= $(_INSTALLDIR)\include

ITKOBJS = \


	$(TMP_DIR)\itk_archetype.obj \
	$(TMP_DIR)\itk_cmds.obj \

	$(TMP_DIR)\itk_option.obj \
	$(TMP_DIR)\itk_util.obj \
!if !$(STATIC_BUILD)
	$(TMP_DIR)\dllEntryPoint.obj \
	$(TMP_DIR)\itk.res \
!endif
!if $(TCL_DOES_STUBS)
	$(TMP_DIR)\itkStubInit.obj
!endif

ITKSTUBOBJS = \
!if $(TCL_DOES_STUBS)
    $(TMP_DIR)\itkStubLib.obj
!endif

GENERICDIR	= $(ROOT)\generic
DOCDIR		= $(ROOT)\doc
WINDIR		= $(ROOT)\win
RCDIR		= $(ROOT)\win\rc
TOOLSDIR	= ..\..\tools

................................................................................
ITK_LLIBS	= $(TCLSTUBLIB) $(TKSTUBLIB) $(ITCLSTUBLIB)

!if exist("$(TCLDIR)\win\coffbase.txt")
ITK_DLLBASE	= -base:@$(TCLDIR)\win\coffbase.txt,itk
!else
ITK_DLLBASE	=
!endif










#---------------------------------------------------------------------
# Compile flags
#---------------------------------------------------------------------

!if $(DEBUG)
!if "$(MACHINE)" == "IA64"
cdebug = -Od -Zi
!else
cdebug = -Z7 -Od -WX
!endif
!else
# This cranks the optimization level up to max.
cdebug = -O2
!endif

# declarations common to all compiler options
cflags = -nologo -c -W3 -YX -Fp$(TMP_DIR)^\

!if $(PENT_0F_ERRATA)
cflags = $(cflags) -QI0f
!endif

!if $(ITAN_B_ERRATA)
cflags = $(cflags) -QIA64_Bx
!endif

!if $(MSVCRT)
crt = -MD$(DBGX)
!else
crt = -MT$(DBGX)







!endif

!if $(TCLINSTALL)
TCL_INCLUDES	= -I"$(TCLDIR)\include"
TK_INCLUDES	= 
!else
TCL_INCLUDES	= -I"$(TCLDIR)\generic" -I"$(TCLDIR)\win"
................................................................................
ITK_EXE_CFLAGS	= $(cdebug) $(cflags) $(crt) $(ITCL_INCLUDES) $(ITK_INCLUDES) \
		$(TCL_INCLUDES) $(TK_INCLUDES) $(ITK_DEFINES)

### By convention, static builds do not use Stubs.  This is just a practice,
### not a technical limitation.
!if $(STATIC_BUILD)
ITK_CFLAGS	= $(ITK_EXE_CFLAGS) -DSTATIC_BUILD $(OPTDEFINES)
!elseif $(TCL_DOES_STUBS)
ITK_CFLAGS	= $(ITK_EXE_CFLAGS) -DUSE_TCL_STUBS -DUSE_TK_STUBS -DUSE_ITCL_STUBS $(OPTDEFINES)
!else
ITK_CFLAGS	= $(ITK_EXE_CFLAGS) $(OPTDEFINES)
!endif

#---------------------------------------------------------------------
# Project specific targets
#---------------------------------------------------------------------

all :     setup $(ITKLIB) $(ITKSTUBLIB)
................................................................................
	@if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR)
	@if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR)

$(ITKLIB): $(ITKOBJS)
!if $(STATIC_BUILD)
	$(lib32) -nologo -machine:$(MACHINE) -out:[email protected] @<<
!else
	$(link32) $(ITK_LFLAGS) $(ITK_DLLBASE) -out:[email protected] $(ITK_LLIBS) @<<
!endif
		$(ITKOBJS)
<<


!if $(TCL_DOES_STUBS)
$(ITKSTUBLIB) : $(ITKSTUBOBJS)
	$(lib32) -nologo -out:[email protected] $(ITKSTUBOBJS)
!endif

install-binaries:
	if not exist "$(_INSTALLDIR)" mkdir "$(_INSTALLDIR)"
	if not exist "$(BIN_INSTALL_DIR)" mkdir "$(BIN_INSTALL_DIR)"
	if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
	if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
	if not exist "$(INCLUDE_INSTALL_DIR)" mkdir "$(INCLUDE_INSTALL_DIR)"
................................................................................
	copy $(ROOT)\generic\itk.h "$(INCLUDE_INSTALL_DIR)"
	copy $(ROOT)\generic\itkDecls.h "$(INCLUDE_INSTALL_DIR)"
	copy $(ROOT)\library\*.* "$(SCRIPT_INSTALL_DIR)"
	echo if {[package vsatisfies 8.0 [package provide Tcl]]} {\
		> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ set add 80>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo } else {>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ set add {}>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo }>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo if {[info exists ::tcl_platform(debug)] ^&^&\
		$$::tcl_platform(debug)	^&^& \>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ ^ ^ ^ ^ [file exists [file join $$dir\
		$(PROJECT)$(ITK_VERSION)$${add}g.dll]]}\
		{>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ package ifneeded Itk $(ITK_DOTVERSION) [list load\
		[file join $$dir $(PROJECT)$(ITK_VERSION)$${add}g.dll]\
		Itk]>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo } else {>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ package ifneeded Itk $(ITK_DOTVERSION) [list load\
		[file join $$dir $(PROJECT)$(ITK_VERSION)$${add}.dll]\
		Itk]>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo }>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo unset add>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"


#---------------------------------------------------------------------
................................................................................
CreateButton(4, "FAQ", ExecFile("http://www.purl.org/NET/Tcl-FAQ/"))
<<
	cd $(MAKEDIR)
	copy "$(DOCTMP_DIR)\$(@B).hlp" "$(OUT_DIR)"
	copy "$(DOCTMP_DIR)\$(@B).cnt" "$(OUT_DIR)"

$(MAN2TCL): $(TCLTOOLSDIR)\$$(@B).c
	$(cc32) -nologo -G4 -ML -O2 -Fo$(@D)\ $(TCLTOOLSDIR)\$(@B).c -link -out:[email protected]

$(HELPRTF): $(MAN2TCL) $(MAN2HELP) $(MAN2HELP2) $(INDEX)
	$(TCLSH) $(MAN2HELP) -bitmap $(BMP_NOPATH) $(PROJECT) $(ITK_VERSION) $(DOCDIR:\=/)

install-docs:
!if exist($(HELPFILE))
	@xcopy /i /y "$(HELPFILE)" "$(DOC_INSTALL_DIR)\"
	@xcopy /i /y "$(HELPCNT)" "$(DOC_INSTALL_DIR)\"
	$(TCLSH) <<
puts "Installing $(PROJECT)'s helpfile contents into Tcl's ..."
set f [open {$(DOC_INSTALL_DIR:\=/)/tcl$(TCL_VERSION).cnt} r]
|






|
|
>
>









|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<













<


<
<
<
<

|


<
|
|
|
|
|
<
<
<
<
<
<
<
|
|


<
<
<
<
<
<
|
<

<
|
|
|
|
|


>
>
|
|
>
|
|




<

<


<

<







 







>
>
>
>
>
>
>
>
>





|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>







 







<
<

|







 







|





<


<







 







|






|



|







 







|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55




56
57
58
59
60
61
62
63
64
65
66
67
68

69
70




71
72
73
74

75
76
77
78
79







80
81
82
83






84

85

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

104

105
106

107

108
109
110
111
112
113
114
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
212
213
214
215
216
217
218


219
220
221
222
223
224
225
226
227
...
247
248
249
250
251
252
253
254
255
256
257
258
259

260
261

262
263
264
265
266
267
268
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
#------------------------------------------------------------------------------
# Visual C++ 6.0+ makefile for [Incr Tk]
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 1993-1998 Lucent Technologies, Inc.
#------------------------------------------------------------------------------
# To build (after setting up Visual C++ command line environment),
#   nmake -f makefile.vc TCLDIR=path_to_tcl_sources TKDIR=path_to_tk_sources
# To install
#   nmake -f makefile.vc TCLDIR=path_to_tcl_sources TKDIR=path_to_tk_sources INSTALLDIR=path_to_install_dir install

!if !exist("makefile.vc")
MSG = ^
You must run this makefile only from the directory it is in.^
Please `cd` to its location first.
!error $(MSG) 
!endif

PROJECT	= itk
PROJECT_REQUIRES_TK = 1
ITCLDIR		= ..\..\itcl
!include "$(ITCLDIR)\win\rules.vc"

!if $(TCLINSTALL)
!message *** Warning: [Incr Tk] requires the source distribution of Tcl to build from,
!message ***    at this time, sorry.  Please set the TCLDIR and TKDIR macros to point
!message ***    to the sources.
!endif

!if [echo REM = This file is generated from makefile.vc > versions.vc]
!endif
!if [echo ITCL_MAJOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V $(ITCLDIR)\generic\itcl.h ITCL_MAJOR_VERSION >> versions.vc]
!endif
!if [echo ITCL_MINOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V $(ITCLDIR)\generic\itcl.h ITCL_MINOR_VERSION >> versions.vc]
!endif
!if [echo ITCL_PATCH_LEVEL = \>> versions.vc] \
   && [nmakehlp -V $(ITCLDIR)\generic\itcl.h ITCL_PATCH_LEVEL >> versions.vc]
!endif
!if [echo ITK_MAJOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V ..\generic\itk.h ITK_MAJOR_VERSION >> versions.vc]
!endif
!if [echo ITK_MINOR_VERSION = \>> versions.vc] \
   && [nmakehlp -V ..\generic\itk.h ITK_MINOR_VERSION >> versions.vc]
!endif
!if [echo ITK_PATCH_LEVEL = \>> versions.vc] \
   && [nmakehlp -V ..\generic\itk.h ITK_PATCH_LEVEL >> versions.vc]
!endif
!include "versions.vc"
ITCL_VERSION   = $(ITCL_MAJOR_VERSION)$(ITCL_MINOR_VERSION)
ITK_VERSION    = $(ITK_MAJOR_VERSION)$(ITK_MINOR_VERSION)
DOTVERSION = $(ITK_PATCH_LEVEL)





BINROOT		= .
ROOT		= ..
STUBPREFIX	= $(PROJECT)stub

PKGINDEX	= "$(TMP_DIR)\pkgIndex.tcl"

ITCLLIBNAME	= itcl$(ITCL_VERSION)$(SUFX).$(EXT)
ITCLLIB		= "$(ITCLDIR)\win\$(OUT_DIR)\$(ITCLLIBNAME)"
ITKIMPLIB	= "$(OUT_DIR)\$(PROJECT)$(ITK_VERSION)$(SUFX).lib"
ITKSTUBLIBNAME	= $(STUBPREFIX)$(ITK_VERSION).lib
ITKSTUBLIB	= "$(OUT_DIR)\$(ITKSTUBLIBNAME)"


ITKLIBNAME	= $(PROJECT)$(ITK_VERSION)$(SUFX).$(EXT)
ITCLIMPLIBNAME	= itcl$(ITCL_VERSION)$(SUFX).$(EXT)




ITKLIB		= "$(OUT_DIR)\$(ITKLIBNAME)"
ITCLIMPLIB	= "$(ITCLDIR)\win\$(BUILDDIRTOP)\$(ITCLIMPLIBNAME)"



TKSTUBLIB	= $(TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib
TKIMPLIB	= $(TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(DBGX).lib
WISH		= $(TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(DBGX).exe
TCL_LIBRARY	= $(TCLDIR)\library
TK_LIBRARY	= $(TKDIR)\library







ITCL_LIBRARY	= $(ITCLDIR:\=/)/library
ITK_LIBRARY	= $(ROOT)/library

ITCLSTUBLIBNAME	= itclstub$(ITCL_VERSION).lib






ITCLSTUBLIB	= $(ITCLDIR)\win\$(BUILDDIRTOP)\$(ITCLSTUBLIBNAME)



BIN_INSTALL_DIR		= $(_INSTALLDIR)\..\bin
DOC_INSTALL_DIR		= $(_INSTALLDIR)\..\doc
LIB_INSTALL_DIR		= $(_INSTALLDIR)
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION)
INCLUDE_INSTALL_DIR	= $(_INSTALLDIR)\..\include

ITKOBJS = \
	$(TMP_DIR)\itkArchBase.obj \
	$(TMP_DIR)\itkArchetype.obj \
	$(TMP_DIR)\itkBase.obj \
	$(TMP_DIR)\itkCmd.obj \
	$(TMP_DIR)\itkHelpers.obj \
	$(TMP_DIR)\itkOption.obj \
	$(TMP_DIR)\itkUtil.obj \
!if !$(STATIC_BUILD)
	$(TMP_DIR)\dllEntryPoint.obj \
	$(TMP_DIR)\itk.res \
!endif

	$(TMP_DIR)\itkStubInit.obj


ITKSTUBOBJS = \

    $(TMP_DIR)\itkStubLib.obj


GENERICDIR	= $(ROOT)\generic
DOCDIR		= $(ROOT)\doc
WINDIR		= $(ROOT)\win
RCDIR		= $(ROOT)\win\rc
TOOLSDIR	= ..\..\tools

................................................................................
ITK_LLIBS	= $(TCLSTUBLIB) $(TKSTUBLIB) $(ITCLSTUBLIB)

!if exist("$(TCLDIR)\win\coffbase.txt")
ITK_DLLBASE	= -base:@$(TCLDIR)\win\coffbase.txt,itk
!else
ITK_DLLBASE	=
!endif

baselibs   = 
# Avoid 'unresolved external symbol __security_cookie' errors.
# c.f. http://support.microsoft.com/?id=894573
!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64"
!if $(VCVERSION) > 1399 && $(VCVERSION) < 1500
baselibs   = $(baselibs) bufferoverflowU.lib
!endif
!endif

#---------------------------------------------------------------------
# Compile flags
#---------------------------------------------------------------------

!if !$(DEBUG)
!if $(OPTIMIZING)
### This cranks the optimization level to maximize speed
cdebug	= -O2 $(OPTIMIZATIONS)
!else
cdebug	= 
!endif
!if $(SYMBOLS)
cdebug	= $(cdebug) -Zi
!endif
!else if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64"
### Warnings are too many, can't support warnings into errors.
cdebug	= -Zi -Od $(DEBUGFLAGS)
!else
cdebug	= -Zi -WX $(DEBUGFLAGS)
!endif

### Declarations common to all compiler options
cwarn = $(WARNINGS) -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE
cflags = -nologo -c $(COMPILERFLAGS) $(cwarn) -Fp$(TMP_DIR)^\

!if $(MSVCRT)
!if $(DEBUG) && !$(UNCHECKED)
crt = -MDd
!else
crt = -MD
!endif
!else
!if $(DEBUG) && !$(UNCHECKED)
crt = -MTd
!else
crt = -MT
!endif
!endif

!if $(TCLINSTALL)
TCL_INCLUDES	= -I"$(TCLDIR)\include"
TK_INCLUDES	= 
!else
TCL_INCLUDES	= -I"$(TCLDIR)\generic" -I"$(TCLDIR)\win"
................................................................................
ITK_EXE_CFLAGS	= $(cdebug) $(cflags) $(crt) $(ITCL_INCLUDES) $(ITK_INCLUDES) \
		$(TCL_INCLUDES) $(TK_INCLUDES) $(ITK_DEFINES)

### By convention, static builds do not use Stubs.  This is just a practice,
### not a technical limitation.
!if $(STATIC_BUILD)
ITK_CFLAGS	= $(ITK_EXE_CFLAGS) -DSTATIC_BUILD $(OPTDEFINES)


!else
ITK_CFLAGS	= $(ITK_EXE_CFLAGS) -DUSE_TCL_STUBS -DUSE_TK_STUBS -DUSE_ITCL_STUBS $(OPTDEFINES)
!endif

#---------------------------------------------------------------------
# Project specific targets
#---------------------------------------------------------------------

all :     setup $(ITKLIB) $(ITKSTUBLIB)
................................................................................
	@if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR)
	@if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR)

$(ITKLIB): $(ITKOBJS)
!if $(STATIC_BUILD)
	$(lib32) -nologo -machine:$(MACHINE) -out:[email protected] @<<
!else
	$(link32) $(ITK_LFLAGS) $(ITK_DLLBASE) -out:[email protected] $(ITK_LLIBS) $(baselibs) @<<
!endif
		$(ITKOBJS)
<<



$(ITKSTUBLIB) : $(ITKSTUBOBJS)
	$(lib32) -nologo -out:[email protected] $(ITKSTUBOBJS)


install-binaries:
	if not exist "$(_INSTALLDIR)" mkdir "$(_INSTALLDIR)"
	if not exist "$(BIN_INSTALL_DIR)" mkdir "$(BIN_INSTALL_DIR)"
	if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
	if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
	if not exist "$(INCLUDE_INSTALL_DIR)" mkdir "$(INCLUDE_INSTALL_DIR)"
................................................................................
	copy $(ROOT)\generic\itk.h "$(INCLUDE_INSTALL_DIR)"
	copy $(ROOT)\generic\itkDecls.h "$(INCLUDE_INSTALL_DIR)"
	copy $(ROOT)\library\*.* "$(SCRIPT_INSTALL_DIR)"
	echo if {[package vsatisfies 8.0 [package provide Tcl]]} {\
		> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ set add 80>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo } else {>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ set add {$(SUFX:g=)}>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo }>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo if {[info exists ::tcl_platform(debug)] ^&^&\
		$$::tcl_platform(debug)	^&^& \>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ ^ ^ ^ ^ [file exists [file join $$dir\
		$(PROJECT)$(ITK_VERSION)$${add}g.dll]]}\
		{>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ package ifneeded Itk $(DOTVERSION) [list load\
		[file join $$dir $(PROJECT)$(ITK_VERSION)$${add}g.dll]\
		Itk]>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo } else {>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo ^ ^ ^ ^ package ifneeded Itk $(DOTVERSION) [list load\
		[file join $$dir $(PROJECT)$(ITK_VERSION)$${add}.dll]\
		Itk]>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo }>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
	echo unset add>> "$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"


#---------------------------------------------------------------------
................................................................................
CreateButton(4, "FAQ", ExecFile("http://www.purl.org/NET/Tcl-FAQ/"))
<<
	cd $(MAKEDIR)
	copy "$(DOCTMP_DIR)\$(@B).hlp" "$(OUT_DIR)"
	copy "$(DOCTMP_DIR)\$(@B).cnt" "$(OUT_DIR)"

$(MAN2TCL): $(TCLTOOLSDIR)\$$(@B).c
	$(cc32) -nologo -G4 -ML -O2 -Fo$(@D)\ $(TCLTOOLSDIR)\$(@B).c $(baselibs) -link -out:[email protected]

$(HELPRTF): $(MAN2TCL) $(MAN2HELP) $(MAN2HELP2) $(INDEX)
	$(TCLSH) $(MAN2HELP) -bitmap $(BMP_NOPATH) $(PROJECT) $(ITK_VERSION) $(DOCDIR:\=/)
	
install-docs:
!if exist($(HELPFILE))
	@xcopy /i /y "$(HELPFILE)" "$(DOC_INSTALL_DIR)\"
	@xcopy /i /y "$(HELPCNT)" "$(DOC_INSTALL_DIR)\"
	$(TCLSH) <<
puts "Installing $(PROJECT)'s helpfile contents into Tcl's ..."
set f [open {$(DOC_INSTALL_DIR:\=/)/tcl$(TCL_VERSION).cnt} r]

Changes to win/nmakehlp.c.


1
2
3
4
5
6

7
8
9
10
11


12




13
14

15
16
17
















18

19
20
21
22



23
24
25

26
27
28
29
30
31
32
33
34
35



36
37
38
39


40
41
42
43
44
45

46


47
48

49


50
51
52
53
54
55
56

57
58
59
60

61
62
63
64
65

66
67
68
69

70
71
72
73
74

75
76
77
78

79
80

81


82
83
84
85
86
87
88
89
90


91

92
93
94










95











96




97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
...
123
124
125
126
127
128
129

130


131
132

133


134
135
136

137


138
139
140
141

142


143


144


145


146


147
148
149
150
151
152
153
154
...
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170
171

172


173
174
175
176
177
178

179


180
181
182

183


184
185
186

187


188
189
190
191

192



193





194
195
196
197

198
199
200
201
202
203
204
...
214
215
216
217
218
219
220

221


222
223

224


225
226
227

228


229
230
231
232

233


234


235


236
237
238
239
240
241
242
243
...
245
246
247
248
249
250
251

252
253
254
255
256
257
258
259
260

261


262
263
264
265
266
267

268


269
270
271

272


273
274
275

276


277
278
279
280

281


282



283
284
285
286

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309


310
311
312
313
314
315
316




317
318
319















320
321





























































































322


323
324




325
326
327
328
329
330
331
332
333



334
335
336
337
338
339
340
341
342















343
344
345
346
347
348
349
350







351
352
353




























354
355
356


































/* ----------------------------------------------------------------------------
 * nmakehlp.c --
 *
 *	This is used to fix limitations within nmake and the environment.
 *
 * Copyright (c) 2002 by David Gravereaux.

 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * ----------------------------------------------------------------------------
 */


#include <windows.h>




#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")

#include <stdio.h>
#include <math.h>

















/* protos */

int CheckForCompilerFeature (const char *option);
int CheckForLinkerFeature (const char *option);
int IsIn (const char *string, const char *substring);
int GrepForDefine (const char *file, const char *string);



DWORD WINAPI ReadFromPipe (LPVOID args);

/* globals */

#define CHUNK	25
#define STATICBUFFERSIZE    1000
typedef struct {
    HANDLE pipe;
    char buffer[STATICBUFFERSIZE];
} pipeinfo;

pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};






/* exitcodes: 0 == no, 1 == yes, 2 == error */
int


main (int argc, char *argv[])
{
    char msg[300];
    DWORD dwWritten;
    int chars;


    /* make sure children (cl.exe and link.exe) are kept quiet. */


    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);


    /* Make sure the compiler and linker aren't effected by the outside world. */


    SetEnvironmentVariable("CL", "");
    SetEnvironmentVariable("LINK", "");

    if (argc > 1 && *argv[1] == '-') {
	switch (*(argv[1]+1)) {
	case 'c':
	    if (argc != 3) {

		chars = wsprintf(msg, "usage: %s -c <compiler option>\n"
			"Tests for whether cl.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);

		return 2;
	    }
	    return CheckForCompilerFeature(argv[2]);
	case 'l':
	    if (argc != 3) {

		chars = wsprintf(msg, "usage: %s -l <linker option>\n"
			"Tests for whether link.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);

		return 2;
	    }
	    return CheckForLinkerFeature(argv[2]);
	case 'f':
	    if (argc == 2) {

		chars = wsprintf(msg, "usage: %s -f <string> <substring>\n"
		    "Find a substring within another\n"
		    "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);

		return 2;
	    } else if (argc == 3) {

		/* if the string is blank, there is no match */


		return 0;
	    } else {
		return IsIn(argv[2], argv[3]);
	    }
	case 'g':
	    if (argc == 2) {
		chars = wsprintf(msg, "usage: %s -g <file> <string>\n"
		    "grep for a #define\n"
		    "exitcodes: integer of the found string (no decimals)\n", argv[0]);


		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);

		return 2;
	    }
	    return GrepForDefine(argv[2], argv[3]);










	}











    }




    chars = wsprintf(msg, "usage: %s -c|-l|-f ...\n"
	    "This is a little helper app to equalize shell differences between WinNT and\n"
	    "Win9x and get nmake.exe to accomplish its job.\n",
	    argv[0]);
    WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
    return 2;
}

int
CheckForCompilerFeature (const char *option)

{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    DWORD threadID;
    char msg[300];
    BOOL ok;
................................................................................
    si.hStdInput = INVALID_HANDLE_VALUE;

    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;


    /* create a non-inheritible pipe. */


    CreatePipe(&Out.pipe, &h, &sa, 0);


    /* dupe the write side, make it inheritible, and close the original. */


    DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);


    /* Same as above, but for the error side. */


    CreatePipe(&Err.pipe, &h, &sa, 0);
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);


    /* base command line */


    strcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X ");


    /* append our option for testing */


    strcat(cmdline, option);


    /* filename to compile, which exists, but is nothing and empty. */


    strcat(cmdline, " .\\nul");

    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */
................................................................................
	    NULL,	    /* Use parent's environment block. */
	    NULL,	    /* Use parent's starting directory. */
	    &si,	    /* Pointer to STARTUPINFO structure. */
	    &pi);	    /* Pointer to PROCESS_INFORMATION structure. */

    if (!ok) {
	DWORD err = GetLastError();

	int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
		FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars],
		(300-chars), 0);
	WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL);
	return 2;
    }


    /* close our references to the write handles that have now been inherited. */


    CloseHandle(si.hStdOutput);
    CloseHandle(si.hStdError);

    WaitForInputIdle(pi.hProcess, 5000);
    CloseHandle(pi.hThread);


    /* start the pipe reader threads. */


    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);


    /* block waiting for the process to end. */


    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);


    /* wait for our pipe to get done reading, should it be a little slow. */


    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
    CloseHandle(pipeThreads[0]);
    CloseHandle(pipeThreads[1]);


    /* look for the commandline warning code in both streams. */



    return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL);





}

int
CheckForLinkerFeature (const char *option)

{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    DWORD threadID;
    char msg[300];
    BOOL ok;
................................................................................
    si.hStdInput = INVALID_HANDLE_VALUE;

    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;


    /* create a non-inheritible pipe. */


    CreatePipe(&Out.pipe, &h, &sa, 0);


    /* dupe the write side, make it inheritible, and close the original. */


    DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);


    /* Same as above, but for the error side. */


    CreatePipe(&Err.pipe, &h, &sa, 0);
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);


    /* base command line */


    strcpy(cmdline, "link.exe -nologo ");


    /* append our option for testing */


    strcat(cmdline, option);

    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */
................................................................................
	    NULL,	    /* Use parent's environment block. */
	    NULL,	    /* Use parent's starting directory. */
	    &si,	    /* Pointer to STARTUPINFO structure. */
	    &pi);	    /* Pointer to PROCESS_INFORMATION structure. */

    if (!ok) {
	DWORD err = GetLastError();

	int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
		FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars],
		(300-chars), 0);
	WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL);
	return 2;
    }


    /* close our references to the write handles that have now been inherited. */


    CloseHandle(si.hStdOutput);
    CloseHandle(si.hStdError);

    WaitForInputIdle(pi.hProcess, 5000);
    CloseHandle(pi.hThread);


    /* start the pipe reader threads. */


    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);


    /* block waiting for the process to end. */


    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);


    /* wait for our pipe to get done reading, should it be a little slow. */


    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
    CloseHandle(pipeThreads[0]);
    CloseHandle(pipeThreads[1]);


    /* look for the commandline warning code in the stderr stream. */


    return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL);



}

DWORD WINAPI
ReadFromPipe (LPVOID args)

{
    pipeinfo *pi = (pipeinfo *) args;
    char *lastBuf = pi->buffer;
    DWORD dwRead;
    BOOL ok;

again:
    if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
	CloseHandle(pi->pipe);
	return -1;
    }
    ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
    if (!ok || dwRead == 0) {
	CloseHandle(pi->pipe);
	return 0;
    }
    lastBuf += dwRead;
    goto again;

    return 0;  /* makes the compiler happy */
}

int


IsIn (const char *string, const char *substring)
{
    return (strstr(string, substring) != NULL);
}

/*
 *  Find a specified #define by name.




 *
 *  If the line is '#define TCL_VERSION "8.5"', it returns
 *  85 as the result.















 */






























































































int


GrepForDefine (const char *file, const char *string)
{




    FILE *f;
    char s1[51], s2[51], s3[51];
    int r = 0;
    double d1;

    f = fopen(file, "rt");
    if (f == NULL) {
	return 0;
    }




    do {
	r = fscanf(f, "%50s", s1);
	if (r == 1 && !strcmp(s1, "#define")) {
	    /* get next two words */
	    r = fscanf(f, "%50s %50s", s2, s3);
	    if (r != 2) continue;
	    /* is the first word what we're looking for? */
	    if (!strcmp(s2, string)) {















		fclose(f);
		/* add 1 past first double quote char. "8.5" */
		d1 = atof(s3 + 1);		  /*    8.5  */
		while (floor(d1) != d1) {
		    d1 *= 10.0;
		}
		return ((int) d1);		  /*    85   */
	    }







	}
    } while (!feof(f));





























    fclose(f);
    return 0;
}


































>
|





>

|
|


>
>

>
>
>
>


>



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
|
|
|
<
>
>
>
|


>









|
>
>
>

<
<

>
>
|





>
|
>
>


>
|
>
>







>
|


|
>





>
|


|
>





>
|
|
|
|
>


>
|
>
>




|

|
|
|
>
>
|
>


|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
|






|
|
|
>







 







>
|
>
>


>
|
>
>
|
|

>
|
>
>

|
|

>
|
>
>
|
>
>
|
>
>
|
>
>
|
>
>
|







 







>
|

|
|

|



>
|
>
>






>
|
>
>



>
|
>
>



>
|
>
>




>
|
>
>
>
|
>
>
>
>
>

|
|
|
>







 







>
|
>
>


>
|
>
>
|
|

>
|
>
>

|
|

>
|
>
>
|
>
>
|
>
>
|







 







>
|

|
|

|



>
|
>
>






>
|
>
>



>
|
>
>



>
|
>
>




>
|
>
>
|
>
>
>

|
|
|
>






|


|











|
|
>
>
|



|

<
>
>
>
>
|
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|

>
>
>
>
|
<
<
<

|
|
<
|
>
>
>

<
<
<
<
<
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
<
<
|
<
|
>
>
>
>
>
>
>
|
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

473
474
475
476
477


478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597



598
599
600

601
602
603
604
605








606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621




622

623
624
625
626
627
628
629
630
631

632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
/*
 * ----------------------------------------------------------------------------
 * nmakehlp.c --
 *
 *	This is used to fix limitations within nmake and the environment.
 *
 * Copyright (c) 2002 by David Gravereaux.
 * Copyright (c) 2006 by Pat Thoyts
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * ----------------------------------------------------------------------------
 */

#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#define NO_SHLWAPI_GDI
#define NO_SHLWAPI_STREAM
#define NO_SHLWAPI_REG
#include <shlwapi.h>
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")
#pragma comment (lib, "shlwapi.lib")
#include <stdio.h>
#include <math.h>

/*
 * This library is required for x64 builds with _some_ versions of MSVC
 */
#if defined(_M_IA64) || defined(_M_AMD64)
#if _MSC_VER >= 1400 && _MSC_VER < 1500
#pragma comment(lib, "bufferoverflowU")
#endif
#endif

/* ISO hack for dumb VC++ */
#ifdef _MSC_VER
#define   snprintf	_snprintf
#endif



/* protos */

static int CheckForCompilerFeature(const char *option);
static int CheckForLinkerFeature(const char *option);
static int IsIn(const char *string, const char *substring);

static int SubstituteFile(const char *substs, const char *filename);
static int QualifyPath(const char *path);
static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
static DWORD WINAPI ReadFromPipe(LPVOID args);

/* globals */

#define CHUNK	25
#define STATICBUFFERSIZE    1000
typedef struct {
    HANDLE pipe;
    char buffer[STATICBUFFERSIZE];
} pipeinfo;

pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};
 
/*
 * exitcodes: 0 == no, 1 == yes, 2 == error
 */



int
main(
    int argc,
    char *argv[])
{
    char msg[300];
    DWORD dwWritten;
    int chars;

    /*
     * Make sure children (cl.exe and link.exe) are kept quiet.
     */

    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);

    /*
     * Make sure the compiler and linker aren't effected by the outside world.
     */

    SetEnvironmentVariable("CL", "");
    SetEnvironmentVariable("LINK", "");

    if (argc > 1 && *argv[1] == '-') {
	switch (*(argv[1]+1)) {
	case 'c':
	    if (argc != 3) {
		chars = snprintf(msg, sizeof(msg) - 1,
		        "usage: %s -c <compiler option>\n"
			"Tests for whether cl.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    }
	    return CheckForCompilerFeature(argv[2]);
	case 'l':
	    if (argc != 3) {
		chars = snprintf(msg, sizeof(msg) - 1,
	       		"usage: %s -l <linker option>\n"
			"Tests for whether link.exe supports an option\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    }
	    return CheckForLinkerFeature(argv[2]);
	case 'f':
	    if (argc == 2) {
		chars = snprintf(msg, sizeof(msg) - 1,
			"usage: %s -f <string> <substring>\n"
			"Find a substring within another\n"
			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    } else if (argc == 3) {
		/*
		 * If the string is blank, there is no match.
		 */

		return 0;
	    } else {
		return IsIn(argv[2], argv[3]);
	    }
	case 's':
	    if (argc == 2) {
		chars = snprintf(msg, sizeof(msg) - 1,
			"usage: %s -s <substitutions file> <file>\n"
			"Perform a set of string map type substutitions on a file\n"
			"exitcodes: 0\n",
			argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
			&dwWritten, NULL);
		return 2;
	    }
	    return SubstituteFile(argv[2], argv[3]);
	case 'V':
	    if (argc != 4) {
		chars = snprintf(msg, sizeof(msg) - 1,
		    "usage: %s -V filename matchstring\n"
		    "Extract a version from a file:\n"
		    "eg: pkgIndex.tcl \"package ifneeded http\"",
		    argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
		    &dwWritten, NULL);
		return 0;
	    }
	    printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'));
	    return 0;
	case 'Q':
	    if (argc != 3) {
		chars = snprintf(msg, sizeof(msg) - 1,
		    "usage: %s -Q path\n"
		    "Emit the fully qualified path\n"
		    "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
		    &dwWritten, NULL);
		return 2;
	    }
	    return QualifyPath(argv[2]);
	}
    }
    chars = snprintf(msg, sizeof(msg) - 1,
	    "usage: %s -c|-f|-l|-Q|-s|-V ...\n"
	    "This is a little helper app to equalize shell differences between WinNT and\n"
	    "Win9x and get nmake.exe to accomplish its job.\n",
	    argv[0]);
    WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
    return 2;
}
 
static int
CheckForCompilerFeature(
    const char *option)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    DWORD threadID;
    char msg[300];
    BOOL ok;
................................................................................
    si.hStdInput = INVALID_HANDLE_VALUE;

    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;

    /*
     * Create a non-inheritible pipe.
     */

    CreatePipe(&Out.pipe, &h, &sa, 0);

    /*
     * Dupe the write side, make it inheritible, and close the original.
     */

    DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /*
     * Same as above, but for the error side.
     */

    CreatePipe(&Err.pipe, &h, &sa, 0);
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /*
     * Base command line.
     */

    lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");

    /*
     * Append our option for testing
     */

    lstrcat(cmdline, option);

    /*
     * Filename to compile, which exists, but is nothing and empty.
     */

    lstrcat(cmdline, " .\\nul");

    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */
................................................................................
	    NULL,	    /* Use parent's environment block. */
	    NULL,	    /* Use parent's starting directory. */
	    &si,	    /* Pointer to STARTUPINFO structure. */
	    &pi);	    /* Pointer to PROCESS_INFORMATION structure. */

    if (!ok) {
	DWORD err = GetLastError();
	int chars = snprintf(msg, sizeof(msg) - 1,
		"Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
		FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
		(300-chars), 0);
	WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
	return 2;
    }

    /*
     * Close our references to the write handles that have now been inherited.
     */

    CloseHandle(si.hStdOutput);
    CloseHandle(si.hStdError);

    WaitForInputIdle(pi.hProcess, 5000);
    CloseHandle(pi.hThread);

    /*
     * Start the pipe reader threads.
     */

    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);

    /*
     * Block waiting for the process to end.
     */

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);

    /*
     * Wait for our pipe to get done reading, should it be a little slow.
     */

    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
    CloseHandle(pipeThreads[0]);
    CloseHandle(pipeThreads[1]);

    /*
     * Look for the commandline warning code in both streams.
     *  - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
     */

    return !(strstr(Out.buffer, "D4002") != NULL
             || strstr(Err.buffer, "D4002") != NULL
             || strstr(Out.buffer, "D9002") != NULL
             || strstr(Err.buffer, "D9002") != NULL
             || strstr(Out.buffer, "D2021") != NULL
             || strstr(Err.buffer, "D2021") != NULL);
}
 
static int
CheckForLinkerFeature(
    const char *option)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    DWORD threadID;
    char msg[300];
    BOOL ok;
................................................................................
    si.hStdInput = INVALID_HANDLE_VALUE;

    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    /*
     * Create a non-inheritible pipe.
     */

    CreatePipe(&Out.pipe, &h, &sa, 0);

    /*
     * Dupe the write side, make it inheritible, and close the original.
     */

    DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /*
     * Same as above, but for the error side.
     */

    CreatePipe(&Err.pipe, &h, &sa, 0);
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /*
     * Base command line.
     */

    lstrcpy(cmdline, "link.exe -nologo ");

    /*
     * Append our option for testing.
     */

    lstrcat(cmdline, option);

    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */
................................................................................
	    NULL,	    /* Use parent's environment block. */
	    NULL,	    /* Use parent's starting directory. */
	    &si,	    /* Pointer to STARTUPINFO structure. */
	    &pi);	    /* Pointer to PROCESS_INFORMATION structure. */

    if (!ok) {
	DWORD err = GetLastError();
	int chars = snprintf(msg, sizeof(msg) - 1,
		"Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
		FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
		(300-chars), 0);
	WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
	return 2;
    }

    /*
     * Close our references to the write handles that have now been inherited.
     */

    CloseHandle(si.hStdOutput);
    CloseHandle(si.hStdError);

    WaitForInputIdle(pi.hProcess, 5000);
    CloseHandle(pi.hThread);

    /*
     * Start the pipe reader threads.
     */

    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);

    /*
     * Block waiting for the process to end.
     */

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);

    /*
     * Wait for our pipe to get done reading, should it be a little slow.
     */

    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
    CloseHandle(pipeThreads[0]);
    CloseHandle(pipeThreads[1]);

    /*
     * Look for the commandline warning code in the stderr stream.
     */

    return !(strstr(Out.buffer, "LNK1117") != NULL ||
	    strstr(Err.buffer, "LNK1117") != NULL ||
	    strstr(Out.buffer, "LNK4044") != NULL ||
	    strstr(Err.buffer, "LNK4044") != NULL);
}
 
static DWORD WINAPI
ReadFromPipe(
    LPVOID args)
{
    pipeinfo *pi = (pipeinfo *) args;
    char *lastBuf = pi->buffer;
    DWORD dwRead;
    BOOL ok;

  again:
    if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
	CloseHandle(pi->pipe);
	return (DWORD)-1;
    }
    ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
    if (!ok || dwRead == 0) {
	CloseHandle(pi->pipe);
	return 0;
    }
    lastBuf += dwRead;
    goto again;

    return 0;  /* makes the compiler happy */
}
 
static int
IsIn(
    const char *string,
    const char *substring)
{
    return (strstr(string, substring) != NULL);
}
 
/*

 * GetVersionFromFile --
 * 	Looks for a match string in a file and then returns the version
 * 	following the match where a version is anything acceptable to
 * 	package provide or package ifneeded.
 */



static const char *
GetVersionFromFile(
    const char *filename,
    const char *match,
    int numdots)
{
    size_t cbBuffer = 100;
    static char szBuffer[100];
    char *szResult = NULL;
    FILE *fp = fopen(filename, "rt");

    if (fp != NULL) {
	/*
	 * Read data until we see our match string.
	 */

	while (fgets(szBuffer, cbBuffer, fp) != NULL) {
	    LPSTR p, q;

	    p = strstr(szBuffer, match);
	    if (p != NULL) {
		/*
		 * Skip to first digit after the match.
		 */

		p += strlen(match);
		while (*p && !isdigit(*p)) {
		    ++p;
		}

		/*
		 * Find ending whitespace.
		 */

		q = p;
		while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q)
			    && (!strchr("ab", q[-1])) || --numdots))) {
		    ++q;
		}

		memcpy(szBuffer, p, q - p);
		szBuffer[q-p] = 0;
		szResult = szBuffer;
		break;
	    }
	}
	fclose(fp);
    }
    return szResult;
}
 
/*
 * List helpers for the SubstituteFile function
 */

typedef struct list_item_t {
    struct list_item_t *nextPtr;
    char * key;
    char * value;
} list_item_t;

/* insert a list item into the list (list may be null) */
static list_item_t *
list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
{
    list_item_t *itemPtr = malloc(sizeof(list_item_t));
    if (itemPtr) {
	itemPtr->key = strdup(key);
	itemPtr->value = strdup(value);
	itemPtr->nextPtr = NULL;

	while(*listPtrPtr) {
	    listPtrPtr = &(*listPtrPtr)->nextPtr;
	}
	*listPtrPtr = itemPtr;
    }
    return itemPtr;
}

static void
list_free(list_item_t **listPtrPtr)
{
    list_item_t *tmpPtr, *listPtr = *listPtrPtr;
    while (listPtr) {
	tmpPtr = listPtr;
	listPtr = listPtr->nextPtr;
	free(tmpPtr->key);
	free(tmpPtr->value);
	free(tmpPtr);
    }
}
 
/*
 * SubstituteFile --
 *	As windows doesn't provide anything useful like sed and it's unreliable
 *	to use the tclsh you are building against (consider x-platform builds -
 *	eg compiling AMD64 target from IX86) we provide a simple substitution
 *	option here to handle autoconf style substitutions.
 *	The substitution file is whitespace and line delimited. The file should
 *	consist of lines matching the regular expression:
 *	  \s*\S+\s+\S*$
 *
 *	Usage is something like:
 *	  nmakehlp -S << $** > [email protected]
 *        @[email protected] $(PACKAGE_NAME)
 *        @[email protected] $(PACKAGE_VERSION)
 *        <<
 */

static int
SubstituteFile(
    const char *substitutions,
    const char *filename)
{
    size_t cbBuffer = 1024;
    static char szBuffer[1024], szCopy[1024];
    char *szResult = NULL;
    list_item_t *substPtr = NULL;
    FILE *fp, *sp;




    fp = fopen(filename, "rt");
    if (fp != NULL) {


	/*
	 * Build a list of substutitions from the first filename
	 */









	sp = fopen(substitutions, "rt");
	if (sp != NULL) {
	    while (fgets(szBuffer, cbBuffer, sp) != NULL) {
		char *ks, *ke, *vs, *ve;
		ks = szBuffer;
		while (ks && *ks && isspace(*ks)) ++ks;
		ke = ks;
		while (ke && *ke && !isspace(*ke)) ++ke;
		vs = ke;
		while (vs && *vs && isspace(*vs)) ++vs;
		ve = vs;
		while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
		*ke = 0, *ve = 0;
		list_insert(&substPtr, ks, vs);
	    }
	    fclose(sp);




	}


	/* debug: dump the list */
#ifdef _DEBUG
	{
	    int n = 0;
	    list_item_t *p = NULL;
	    for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
		fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
	    }

	}
#endif

	/*
	 * Run the substitutions over each line of the input
	 */

	while (fgets(szBuffer, cbBuffer, fp) != NULL) {
	    list_item_t *p = NULL;
	    for (p = substPtr; p != NULL; p = p->nextPtr) {
		char *m = strstr(szBuffer, p->key);
		if (m) {
		    char *cp, *op, *sp;
		    cp = szCopy;
		    op = szBuffer;
		    while (op != m) *cp++ = *op++;
		    sp = p->value;
		    while (sp && *sp) *cp++ = *sp++;
		    op += strlen(p->key);
		    while (*op) *cp++ = *op++;
		    *cp = 0;
		    memcpy(szBuffer, szCopy, sizeof(szCopy));
		}
	    }
	    printf(szBuffer);
	}

	list_free(&substPtr);
    }
    fclose(fp);
    return 0;
}
 
/*
 * QualifyPath --
 *
 *	This composes the current working directory with a provided path
 *	and returns the fully qualified and normalized path.
 *	Mostly needed to setup paths for testing.
 */

static int
QualifyPath(
    const char *szPath)
{
    char szCwd[MAX_PATH + 1];
    char szTmp[MAX_PATH + 1];
    char *p;
    GetCurrentDirectory(MAX_PATH, szCwd);
    while ((p = strchr(szPath, '/')) && *p)
	*p = '\\';
    PathCombine(szTmp, szCwd, szPath);
    PathCanonicalize(szCwd, szTmp);
    printf("%s\n", szCwd);
    return 0;
}

/*
 * Local variables:
 *   mode: c
 *   c-basic-offset: 4
 *   fill-column: 78
 *   indent-tabs-mode: t
 *   tab-width: 8
 * End:
 */