/ Check-in [50673dda]
Login

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

Overview
Comment:Add tool capable of downloading a TclKit (and its associated SDK) on Windows.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | omit-awk
Files: files | file ages | folders
SHA1: 50673ddaf813335777673fa8585997a7551e5323
User & Date: mistachkin 2015-10-09 17:36:06
Context
2015-10-09
18:48
Tweak batch tool added in the previous check-in to permit the base URI to be overridden. check-in: 1d2f82df user: mistachkin tags: omit-awk
17:36
Add tool capable of downloading a TclKit (and its associated SDK) on Windows. check-in: 50673dda user: mistachkin tags: omit-awk
2015-10-07
12:36
Convert the tool/tostr.awk script into tool/tostr.tcl. Remove two obsolete Makefiles. Purge NAWK from the configure script and from unix makefiles. There are still two uses of NAWK in Makefile.msc. check-in: 5b677521 user: drh tags: omit-awk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Added tool/GetFile.cs.

            1  +/*
            2  +** 2015 October 7
            3  +**
            4  +** The author disclaims copyright to this source code.  In place of
            5  +** a legal notice, here is a blessing:
            6  +**
            7  +**    May you do good and not evil.
            8  +**    May you find forgiveness for yourself and forgive others.
            9  +**    May you share freely, never taking more than you give.
           10  +**
           11  +*************************************************************************
           12  +** This file contains C# code to download a single file based on a URI.
           13  +*/
           14  +
           15  +using System;
           16  +using System.ComponentModel;
           17  +using System.Diagnostics;
           18  +using System.IO;
           19  +using System.Net;
           20  +using System.Reflection;
           21  +using System.Runtime.InteropServices;
           22  +using System.Threading;
           23  +
           24  +///////////////////////////////////////////////////////////////////////////////
           25  +
           26  +#region Assembly Metadata
           27  +[assembly: AssemblyTitle("GetFile Tool")]
           28  +[assembly: AssemblyDescription("Download a single file based on a URI.")]
           29  +[assembly: AssemblyCompany("SQLite Development Team")]
           30  +[assembly: AssemblyProduct("SQLite")]
           31  +[assembly: AssemblyCopyright("Public Domain")]
           32  +[assembly: ComVisible(false)]
           33  +[assembly: Guid("5c4b3728-1693-4a33-a218-8e6973ca15a6")]
           34  +[assembly: AssemblyVersion("1.0.*")]
           35  +
           36  +#if DEBUG
           37  +[assembly: AssemblyConfiguration("Debug")]
           38  +#else
           39  +[assembly: AssemblyConfiguration("Release")]
           40  +#endif
           41  +#endregion
           42  +
           43  +///////////////////////////////////////////////////////////////////////////////
           44  +
           45  +namespace GetFile
           46  +{
           47  +    /// <summary>
           48  +    /// This enumeration is used to represent all the possible exit codes from
           49  +    /// this tool.
           50  +    /// </summary>
           51  +    internal enum ExitCode
           52  +    {
           53  +        /// <summary>
           54  +        /// The file download was a success.
           55  +        /// </summary>
           56  +        Success = 0,
           57  +
           58  +        /// <summary>
           59  +        /// The command line arguments are missing (i.e. null).  Generally,
           60  +        /// this should not happen.
           61  +        /// </summary>
           62  +        MissingArgs = 1,
           63  +
           64  +        /// <summary>
           65  +        /// The wrong number of command line arguments was supplied.
           66  +        /// </summary>
           67  +        WrongNumArgs = 2,
           68  +
           69  +        /// <summary>
           70  +        /// The URI specified on the command line could not be parsed as a
           71  +        /// supported absolute URI.
           72  +        /// </summary>
           73  +        BadUri = 3,
           74  +
           75  +        /// <summary>
           76  +        /// The file name portion of the URI specified on the command line
           77  +        /// could not be extracted from it.
           78  +        /// </summary>
           79  +        BadFileName = 4,
           80  +
           81  +        /// <summary>
           82  +        /// The temporary directory is either invalid (i.e. null) or does not
           83  +        /// represent an available directory.
           84  +        /// </summary>
           85  +        BadTempPath = 5,
           86  +
           87  +        /// <summary>
           88  +        /// An exception was caught in <see cref="Main" />.  Generally, this
           89  +        /// should not happen.
           90  +        /// </summary>
           91  +        Exception = 6,
           92  +
           93  +        /// <summary>
           94  +        /// The file download was canceled.  This tool does not make use of
           95  +        /// the <see cref="WebClient.CancelAsync" /> method; therefore, this
           96  +        /// should not happen.
           97  +        /// </summary>
           98  +        DownloadCanceled = 7,
           99  +
          100  +        /// <summary>
          101  +        /// The file download encountered an error.  Further information about
          102  +        /// this error should be displayed on the console.
          103  +        /// </summary>
          104  +        DownloadError = 8
          105  +    }
          106  +
          107  +    ///////////////////////////////////////////////////////////////////////////
          108  +
          109  +    internal static class Program
          110  +    {
          111  +        #region Private Data
          112  +        /// <summary>
          113  +        /// This is used to synchronize multithreaded access to the
          114  +        /// <see cref="previousPercent" /> and <see cref="exitCode"/>
          115  +        /// fields.
          116  +        /// </summary>
          117  +        private static readonly object syncRoot = new object();
          118  +
          119  +        ///////////////////////////////////////////////////////////////////////
          120  +
          121  +        /// <summary>
          122  +        /// This event will be signed when the file download has completed,
          123  +        /// even if the file download itself was canceled or unsuccessful.
          124  +        /// </summary>
          125  +        private static EventWaitHandle doneEvent;
          126  +
          127  +        ///////////////////////////////////////////////////////////////////////
          128  +
          129  +        /// <summary>
          130  +        /// The previous file download completion percentage seen by the
          131  +        /// <see cref="DownloadProgressChanged" /> event handler.  This value
          132  +        /// is never decreased, nor is it ever reset to zero.
          133  +        /// </summary>
          134  +        private static int previousPercent = 0;
          135  +
          136  +        ///////////////////////////////////////////////////////////////////////
          137  +
          138  +        /// <summary>
          139  +        /// This will be the exit code returned by this tool after the file
          140  +        /// download completes, successfully or otherwise.  This value is only
          141  +        /// changed by the <see cref="DownloadFileCompleted" /> event handler.
          142  +        /// </summary>
          143  +        private static ExitCode exitCode = ExitCode.Success;
          144  +        #endregion
          145  +
          146  +        ///////////////////////////////////////////////////////////////////////
          147  +
          148  +        #region Private Support Methods
          149  +        /// <summary>
          150  +        /// This method displays an error message to the console and/or
          151  +        /// displays the command line usage information for this tool.
          152  +        /// </summary>
          153  +        /// <param name="message">
          154  +        /// The error message to display, if any.
          155  +        /// </param>
          156  +        /// <param name="usage">
          157  +        /// Non-zero to display the command line usage information.
          158  +        /// </param>
          159  +        private static void Error(
          160  +            string message,
          161  +            bool usage
          162  +            )
          163  +        {
          164  +            if (message != null)
          165  +                Console.WriteLine(message);
          166  +
          167  +            string fileName = Path.GetFileName(
          168  +                Process.GetCurrentProcess().MainModule.FileName);
          169  +
          170  +            Console.WriteLine(String.Format("usage: {0} <uri>", fileName));
          171  +        }
          172  +
          173  +        ///////////////////////////////////////////////////////////////////////
          174  +
          175  +        /// <summary>
          176  +        /// This method attempts to determine the file name portion of the
          177  +        /// specified URI.
          178  +        /// </summary>
          179  +        /// <param name="uri">
          180  +        /// The URI to process.
          181  +        /// </param>
          182  +        /// <returns>
          183  +        /// The file name portion of the specified URI -OR- null if it cannot
          184  +        /// be determined.
          185  +        /// </returns>
          186  +        private static string GetFileName(
          187  +            Uri uri
          188  +            )
          189  +        {
          190  +            if (uri == null)
          191  +                return null;
          192  +
          193  +            string pathAndQuery = uri.PathAndQuery;
          194  +
          195  +            if (String.IsNullOrEmpty(pathAndQuery))
          196  +                return null;
          197  +
          198  +            int index = pathAndQuery.LastIndexOf('/');
          199  +
          200  +            if ((index < 0) || (index == pathAndQuery.Length))
          201  +                return null;
          202  +
          203  +            return pathAndQuery.Substring(index + 1);
          204  +        }
          205  +        #endregion
          206  +
          207  +        ///////////////////////////////////////////////////////////////////////
          208  +
          209  +        #region Private Event Handlers
          210  +        /// <summary>
          211  +        /// This method is an event handler that is called when the file
          212  +        /// download completion percentage changes.  It will display progress
          213  +        /// on the console.  Special care is taken to make sure that progress
          214  +        /// events are not displayed out-of-order, even if duplicate and/or
          215  +        /// out-of-order events are received.
          216  +        /// </summary>
          217  +        /// <param name="sender">
          218  +        /// The source of the event.
          219  +        /// </param>
          220  +        /// <param name="e">
          221  +        /// Information for the event being processed.
          222  +        /// </param>
          223  +        private static void DownloadProgressChanged(
          224  +            object sender,
          225  +            DownloadProgressChangedEventArgs e
          226  +            )
          227  +        {
          228  +            if (e != null)
          229  +            {
          230  +                int percent = e.ProgressPercentage;
          231  +
          232  +                lock (syncRoot)
          233  +                {
          234  +                    if (percent > previousPercent)
          235  +                    {
          236  +                        Console.Write('.');
          237  +
          238  +                        if ((percent % 10) == 0)
          239  +                            Console.Write(" {0}% ", percent);
          240  +
          241  +                        previousPercent = percent;
          242  +                    }
          243  +                }
          244  +            }
          245  +        }
          246  +
          247  +        ///////////////////////////////////////////////////////////////////////
          248  +
          249  +        /// <summary>
          250  +        /// This method is an event handler that is called when the file
          251  +        /// download has completed, successfully or otherwise.  It will
          252  +        /// display the overall result of the file download on the console,
          253  +        /// including any <see cref="Exception" /> information, if applicable.
          254  +        /// The <see cref="exitCode" /> field is changed by this method to
          255  +        /// indicate the overall result of the file download and the event
          256  +        /// within the <see cref="doneEvent" /> field will be signaled.
          257  +        /// </summary>
          258  +        /// <param name="sender">
          259  +        /// The source of the event.
          260  +        /// </param>
          261  +        /// <param name="e">
          262  +        /// Information for the event being processed.
          263  +        /// </param>
          264  +        private static void DownloadFileCompleted(
          265  +            object sender,
          266  +            AsyncCompletedEventArgs e
          267  +            )
          268  +        {
          269  +            if (e != null)
          270  +            {
          271  +                lock (syncRoot)
          272  +                {
          273  +                    if (previousPercent < 100)
          274  +                        Console.Write(' ');
          275  +                }
          276  +
          277  +                if (e.Cancelled)
          278  +                {
          279  +                    Console.WriteLine("Canceled");
          280  +
          281  +                    lock (syncRoot)
          282  +                    {
          283  +                        exitCode = ExitCode.DownloadCanceled;
          284  +                    }
          285  +                }
          286  +                else
          287  +                {
          288  +                    Exception error = e.Error;
          289  +
          290  +                    if (error != null)
          291  +                    {
          292  +                        Console.WriteLine("Error: {0}", error);
          293  +
          294  +                        lock (syncRoot)
          295  +                        {
          296  +                            exitCode = ExitCode.DownloadError;
          297  +                        }
          298  +                    }
          299  +                    else
          300  +                    {
          301  +                        Console.WriteLine("Done");
          302  +                    }
          303  +                }
          304  +            }
          305  +
          306  +            if (doneEvent != null)
          307  +                doneEvent.Set();
          308  +        }
          309  +        #endregion
          310  +
          311  +        ///////////////////////////////////////////////////////////////////////
          312  +
          313  +        #region Program Entry Point
          314  +        /// <summary>
          315  +        /// This is the entry-point for this tool.  It handles processing the
          316  +        /// command line arguments, setting up the web client, downloading the
          317  +        /// file, and saving it to the file system.
          318  +        /// </summary>
          319  +        /// <param name="args">
          320  +        /// The command line arguments.
          321  +        /// </param>
          322  +        /// <returns>
          323  +        /// Zero upon success; non-zero on failure.  This will be one of the
          324  +        /// values from the <see cref="ExitCode" /> enumeration.
          325  +        /// </returns>
          326  +        private static int Main(
          327  +            string[] args
          328  +            )
          329  +        {
          330  +            //
          331  +            // NOTE: Sanity check the command line arguments.
          332  +            //
          333  +            if (args == null)
          334  +            {
          335  +                Error(null, true);
          336  +                return (int)ExitCode.MissingArgs;
          337  +            }
          338  +
          339  +            if (args.Length != 1)
          340  +            {
          341  +                Error(null, true);
          342  +                return (int)ExitCode.WrongNumArgs;
          343  +            }
          344  +
          345  +            //
          346  +            // NOTE: Attempt to convert the first (and only) command line
          347  +            //       argument to an absolute URI.
          348  +            //
          349  +            Uri uri;
          350  +
          351  +            if (!Uri.TryCreate(args[0], UriKind.Absolute, out uri))
          352  +            {
          353  +                Error("First argument is not an absolute URI.", false);
          354  +                return (int)ExitCode.BadUri;
          355  +            }
          356  +
          357  +            //
          358  +            // NOTE: Attempt to extract the file name portion of the URI we
          359  +            //       just created.
          360  +            //
          361  +            string fileName = GetFileName(uri);
          362  +
          363  +            if (fileName == null)
          364  +            {
          365  +                Error("Could not extract the file name from the URI.", false);
          366  +                return (int)ExitCode.BadFileName;
          367  +            }
          368  +
          369  +            //
          370  +            // NOTE: Grab the temporary path setup for this process.  If it is
          371  +            //       unavailable, we will not continue.
          372  +            //
          373  +            string directory = Path.GetTempPath();
          374  +
          375  +            if (String.IsNullOrEmpty(directory) ||
          376  +                !Directory.Exists(directory))
          377  +            {
          378  +                Error("Temporary directory is invalid or unavailable.", false);
          379  +                return (int)ExitCode.BadTempPath;
          380  +            }
          381  +
          382  +            try
          383  +            {
          384  +                using (WebClient webClient = new WebClient())
          385  +                {
          386  +                    //
          387  +                    // NOTE: Create the event used to signal completion of the
          388  +                    //       file download.
          389  +                    //
          390  +                    doneEvent = new ManualResetEvent(false);
          391  +
          392  +                    //
          393  +                    // NOTE: Hookup the event handlers we care about on the web
          394  +                    //       client.  These are necessary because the file is
          395  +                    //       downloaded asynchronously.
          396  +                    //
          397  +                    webClient.DownloadProgressChanged +=
          398  +                        new DownloadProgressChangedEventHandler(
          399  +                            DownloadProgressChanged);
          400  +
          401  +                    webClient.DownloadFileCompleted +=
          402  +                        new AsyncCompletedEventHandler(
          403  +                            DownloadFileCompleted);
          404  +
          405  +                    //
          406  +                    // NOTE: Build the fully qualified path and file name,
          407  +                    //       within the temporary directory, where the file to
          408  +                    //       be downloaded will be saved.
          409  +                    //
          410  +                    fileName = Path.Combine(directory, fileName);
          411  +
          412  +                    //
          413  +                    // NOTE: If the file name already exists (in the temporary)
          414  +                    //       directory, delete it.
          415  +                    //
          416  +                    // TODO: Perhaps an error should be raised here instead?
          417  +                    //
          418  +                    if (File.Exists(fileName))
          419  +                        File.Delete(fileName);
          420  +
          421  +                    //
          422  +                    // NOTE: After kicking off the asynchronous file download
          423  +                    //       process, wait [forever] until the "done" event is
          424  +                    //       signaled.
          425  +                    //
          426  +                    Console.WriteLine(
          427  +                        "Downloading \"{0}\" to \"{1}\"...", uri, fileName);
          428  +
          429  +                    webClient.DownloadFileAsync(uri, fileName);
          430  +                    doneEvent.WaitOne();
          431  +                }
          432  +
          433  +                lock (syncRoot)
          434  +                {
          435  +                    return (int)exitCode;
          436  +                }
          437  +            }
          438  +            catch (Exception e)
          439  +            {
          440  +                //
          441  +                // NOTE: An exception was caught.  Report it via the console
          442  +                //       and return failure.
          443  +                //
          444  +                Error(e.ToString(), false);
          445  +                return (int)ExitCode.Exception;
          446  +            }
          447  +        }
          448  +        #endregion
          449  +    }
          450  +}

Added tool/GetTclKit.bat.

            1  +@ECHO OFF
            2  +
            3  +::
            4  +:: GetTclKit.bat --
            5  +::
            6  +:: TclKit Download Tool
            7  +::
            8  +
            9  +SETLOCAL
           10  +
           11  +REM SET __ECHO=ECHO
           12  +REM SET __ECHO2=ECHO
           13  +REM SET __ECHO3=ECHO
           14  +IF NOT DEFINED _AECHO (SET _AECHO=REM)
           15  +IF NOT DEFINED _CECHO (SET _CECHO=REM)
           16  +IF NOT DEFINED _VECHO (SET _VECHO=REM)
           17  +
           18  +SET OVERWRITE=^>
           19  +IF DEFINED __ECHO SET OVERWRITE=^^^>
           20  +
           21  +SET APPEND=^>^>
           22  +IF DEFINED __ECHO SET APPEND=^^^>^^^>
           23  +
           24  +SET PROCESSOR=%1
           25  +
           26  +IF DEFINED PROCESSOR (
           27  +  CALL :fn_UnquoteVariable PROCESSOR
           28  +) ELSE (
           29  +  GOTO usage
           30  +)
           31  +
           32  +%_VECHO% Processor = '%PROCESSOR%'
           33  +
           34  +SET DUMMY2=%2
           35  +
           36  +IF DEFINED DUMMY2 (
           37  +  GOTO usage
           38  +)
           39  +
           40  +SET ROOT=%~dp0\..
           41  +SET ROOT=%ROOT:\\=\%
           42  +
           43  +%_VECHO% Root = '%ROOT%'
           44  +
           45  +SET TOOLS=%~dp0
           46  +SET TOOLS=%TOOLS:~0,-1%
           47  +
           48  +%_VECHO% Tools = '%TOOLS%'
           49  +
           50  +IF NOT DEFINED windir (
           51  +  ECHO The windir environment variable must be set first.
           52  +  GOTO errors
           53  +)
           54  +
           55  +%_VECHO% WinDir = '%windir%'
           56  +
           57  +IF NOT DEFINED TEMP (
           58  +  ECHO The TEMP environment variable must be set first.
           59  +  GOTO errors
           60  +)
           61  +
           62  +%_VECHO% Temp = '%TEMP%'
           63  +
           64  +SET TCLKIT_URI=http://tclsh.com/
           65  +
           66  +%_VECHO% TclKitUri = '%TCLKIT_URI%'
           67  +
           68  +IF /I "%PROCESSOR%" == "x86" (
           69  +  CALL :fn_TclKitX86Variables
           70  +) ELSE IF /I "%PROCESSOR%" == "x64" (
           71  +  CALL :fn_TclKitX64Variables
           72  +) ELSE (
           73  +  GOTO usage
           74  +)
           75  +
           76  +%_VECHO% TclKitPatchLevel = '%TCLKIT_PATCHLEVEL%'
           77  +%_VECHO% TclKitNoSdk = '%TCLKIT_NOSDK%'
           78  +%_VECHO% TclKitExe = '%TCLKIT_EXE%'
           79  +%_VECHO% TclKitLib = '%TCLKIT_LIB%'
           80  +%_VECHO% TclKitSdk = '%TCLKIT_SDK%'
           81  +%_VECHO% TclKitSdkZip = '%TCLKIT_SDK_ZIP%'
           82  +%_VECHO% TclKitFiles = '%TCLKIT_FILES%'
           83  +
           84  +CALL :fn_ResetErrorLevel
           85  +
           86  +FOR %%T IN (csc.exe) DO (
           87  +  SET %%T_PATH=%%~dp$PATH:T
           88  +)
           89  +
           90  +%_VECHO% Csc.exe_PATH = '%csc.exe_PATH%'
           91  +
           92  +IF DEFINED csc.exe_PATH (
           93  +  GOTO skip_addToPath
           94  +)
           95  +
           96  +IF DEFINED FRAMEWORKDIR (
           97  +  REM Use the existing .NET Framework directory...
           98  +) ELSE IF EXIST "%windir%\Microsoft.NET\Framework64\v2.0.50727" (
           99  +  SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework64\v2.0.50727
          100  +) ELSE IF EXIST "%windir%\Microsoft.NET\Framework64\v3.5" (
          101  +  SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework64\v3.5
          102  +) ELSE IF EXIST "%windir%\Microsoft.NET\Framework64\v4.0.30319" (
          103  +  SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework64\v4.0.30319
          104  +) ELSE IF EXIST "%windir%\Microsoft.NET\Framework\v2.0.50727" (
          105  +  SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework\v2.0.50727
          106  +) ELSE IF EXIST "%windir%\Microsoft.NET\Framework\v3.5" (
          107  +  SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework\v3.5
          108  +) ELSE IF EXIST "%windir%\Microsoft.NET\Framework\v4.0.30319" (
          109  +  SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework\v4.0.30319
          110  +) ELSE (
          111  +  ECHO No suitable version of the .NET Framework appears to be installed.
          112  +  GOTO errors
          113  +)
          114  +
          115  +%_VECHO% FrameworkDir = '%FRAMEWORKDIR%'
          116  +
          117  +IF NOT EXIST "%FRAMEWORKDIR%\csc.exe" (
          118  +  ECHO The file "%FRAMEWORKDIR%\csc.exe" is missing.
          119  +  GOTO errors
          120  +)
          121  +
          122  +SET PATH=%FRAMEWORKDIR%;%PATH%
          123  +
          124  +:skip_addToPath
          125  +
          126  +%__ECHO% csc.exe "/out:%TEMP%\GetFile.exe" /target:exe "%TOOLS%\GetFile.cs"
          127  +
          128  +IF ERRORLEVEL 1 (
          129  +  ECHO Compilation of "%TOOLS%\GetFile.cs" failed.
          130  +  GOTO errors
          131  +)
          132  +
          133  +FOR %%F IN (%TCLKIT_FILES%) DO (
          134  +  IF NOT EXIST "%%F" (
          135  +    %__ECHO% "%TEMP%\GetFile.exe" "%TCLKIT_URI%%%F"
          136  +
          137  +    IF ERRORLEVEL 1 (
          138  +      ECHO Download of "%%F" from "%TCLKIT_URI%" failed.
          139  +      GOTO errors
          140  +    )
          141  +  )
          142  +)
          143  +
          144  +IF DEFINED TCLKIT_NOSDK GOTO skip_sdkUnZip
          145  +
          146  +IF NOT EXIST "%TEMP%\%TCLKIT_SDK%" (
          147  +  %__ECHO% MKDIR "%TEMP%\%TCLKIT_SDK%"
          148  +
          149  +  IF ERRORLEVEL 1 (
          150  +    ECHO Could not create directory "%TEMP%\%TCLKIT_SDK%".
          151  +    GOTO errors
          152  +  )
          153  +)
          154  +
          155  +%__ECHO% "%TEMP%\unzip.exe" -o "%TEMP%\%TCLKIT_SDK_ZIP%" -d "%TEMP%\%TCLKIT_SDK%"
          156  +
          157  +IF ERRORLEVEL 1 (
          158  +  ECHO Could not unzip "%TEMP%\%TCLKIT_SDK_ZIP%" to "%TEMP%\%TCLKIT_SDK%".
          159  +  GOTO errors
          160  +)
          161  +
          162  +:skip_sdkUnZip
          163  +
          164  +%__ECHO% ECHO SET TCLSH_CMD=%TEMP%\%TCLKIT_EXE%%OVERWRITE%"%ROOT%\SetTclKitEnv.bat"
          165  +
          166  +IF DEFINED TCLKIT_NOSDK GOTO skip_sdkVariables
          167  +
          168  +%__ECHO% ECHO SET TCLINCDIR=%TEMP%\%TCLKIT_SDK%\include%APPEND%"%ROOT%\SetTclKitEnv.bat"
          169  +%__ECHO% ECHO SET TCLLIBDIR=%TEMP%\%TCLKIT_SDK%\lib%APPEND%"%ROOT%\SetTclKitEnv.bat"
          170  +%__ECHO% ECHO SET LIBTCL=%TCLKIT_LIB%%APPEND%"%ROOT%\SetTclKitEnv.bat"
          171  +
          172  +:skip_sdkVariables
          173  +
          174  +GOTO no_errors
          175  +
          176  +:fn_TclKitX86Variables
          177  +  IF NOT DEFINED TCLKIT_PATCHLEVEL (
          178  +    SET TCLKIT_PATCHLEVEL=8.6.4
          179  +  )
          180  +  SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe
          181  +  SET TCLKIT_LIB=libtclkit%TCLKIT_PATCHLEVEL:.=%.lib
          182  +  SET TCLKIT_SDK=libtclkit-sdk-x86-%TCLKIT_PATCHLEVEL%
          183  +  SET TCLKIT_SDK_ZIP=%TCLKIT_SDK%.zip
          184  +  SET TCLKIT_FILES=%TCLKIT_EXE% unzip.exe %TCLKIT_SDK_ZIP%
          185  +  GOTO :EOF
          186  +
          187  +:fn_TclKitX64Variables
          188  +  IF NOT DEFINED TCLKIT_PATCHLEVEL (
          189  +    REM
          190  +    REM NOTE: By default, use latest available version of the TclKit SDK
          191  +    REM       for x64.  However, the "default" TclKit executable for x86
          192  +    REM       is still used here because it is the only one "well-known"
          193  +    REM       to be available for download.
          194  +    REM
          195  +    SET TCLKIT_PATCHLEVEL=8.6.3
          196  +    SET TCLKIT_EXE=tclkit-8.6.4.exe
          197  +  ) ELSE (
          198  +    SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe
          199  +  )
          200  +  SET TCLKIT_LIB=libtclkit%TCLKIT_PATCHLEVEL:.=%.lib
          201  +  SET TCLKIT_SDK=libtclkit-sdk-x64-%TCLKIT_PATCHLEVEL%
          202  +  SET TCLKIT_SDK_ZIP=%TCLKIT_SDK%.zip
          203  +  SET TCLKIT_FILES=%TCLKIT_EXE% unzip.exe %TCLKIT_SDK_ZIP%
          204  +  GOTO :EOF
          205  +
          206  +:fn_UnquoteVariable
          207  +  IF NOT DEFINED %1 GOTO :EOF
          208  +  SETLOCAL
          209  +  SET __ECHO_CMD=ECHO %%%1%%
          210  +  FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO (
          211  +    SET VALUE=%%V
          212  +  )
          213  +  SET VALUE=%VALUE:"=%
          214  +  REM "
          215  +  ENDLOCAL && SET %1=%VALUE%
          216  +  GOTO :EOF
          217  +
          218  +:fn_ResetErrorLevel
          219  +  VERIFY > NUL
          220  +  GOTO :EOF
          221  +
          222  +:fn_SetErrorLevel
          223  +  VERIFY MAYBE 2> NUL
          224  +  GOTO :EOF
          225  +
          226  +:usage
          227  +  ECHO.
          228  +  ECHO Usage: %~nx0 ^<processor^>
          229  +  ECHO.
          230  +  ECHO The only supported values for processor are "x86" and "x64".
          231  +  GOTO errors
          232  +
          233  +:errors
          234  +  CALL :fn_SetErrorLevel
          235  +  ENDLOCAL
          236  +  ECHO.
          237  +  ECHO Failure, errors were encountered.
          238  +  GOTO end_of_file
          239  +
          240  +:no_errors
          241  +  CALL :fn_ResetErrorLevel
          242  +  ENDLOCAL
          243  +  ECHO.
          244  +  ECHO Success, no errors were encountered.
          245  +  GOTO end_of_file
          246  +
          247  +:end_of_file
          248  +%__ECHO% EXIT /B %ERRORLEVEL%