summary refs log tree commit diff stats
path: root/lib/system/memory.nim
blob: ebda60d8d1670dda77688c80130e52222290b370 (plain) (blame)
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
{.push stack_trace: off.}

const useLibC = not defined(nimNoLibc)

when useLibC:
  import ansi_c

proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline.} =
  when useLibC:
    c_memcpy(dest, source, cast[csize_t](size))
  else:
    let d = cast[ptr UncheckedArray[byte]](dest)
    let s = cast[ptr UncheckedArray[byte]](source)
    var i = 0
    while i < size:
      d[i] = s[i]
      inc i

proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} =
  when useLibC:
    c_memset(a, v, cast[csize_t](size))
  else:
    let a = cast[ptr UncheckedArray[byte]](a)
    var i = 0
    let v = cast[byte](v)
    while i < size:
      a[i] = v
      inc i

proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inline.} =
  nimSetMem(p, 0, size)

proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline.} =
  when useLibC:
    c_memcmp(a, b, cast[csize_t](size))
  else:
    let a = cast[ptr UncheckedArray[byte]](a)
    let b = cast[ptr UncheckedArray[byte]](b)
    var i = 0
    while i < size:
      let d = a[i].cint - b[i].cint
      if d != 0: return d
      inc i

proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline.} =
  when useLibC:
    cast[int](c_strlen(a))
  else:
    var a = cast[ptr byte](a)
    while a[] != 0:
      a = cast[ptr byte](cast[uint](a) + 1)
      inc result

{.pop.}
ighlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
; $LynxId: lynx.iss,v 1.37 2022/12/29 00:23:53 tom Exp $
; vile:ts=4 sw=4 notabinsert fk=8bit
;
; This is the BASE script for different flavors of the installer for Lynx.
; It can be overridden to select different source-executables (and their associated
; screen library, e.g., pdcurses or slang).
;
; The script assumes environment variables have been set, e.g., to point to
; data which is used by the installer:
;
; LYNX_BINDIR - directory containing lynx.exe (or different names)
; LYNX_DLLSDIR - directory containing curses or slang dlls.
; LYNX_DOCSDIR - files and subdirectories installed from Unix with "make install-doc"
; LYNX_HELPDIR - files and subdirectories installed from Unix with "make install-help"

#include "version.iss"

#ifndef MyAppExeName
#define MyAppExeName "lynx.exe"
#endif

#if Ver < 0x5060100
#define MySendTo '{sendto}\' + myAppName + '.lnk'
#else
#define MySendTo '{usersendto}\' + myAppName + '.lnk'
#endif
#define MyQuickLaunch '{userappdata}\Microsoft\Internet Explorer\Quick Launch\' + myAppName + '.lnk'

#ifndef SourceExeName
#define SourceExeName "lynx-default.exe"
#endif

#ifndef NoScreenDll
#ifndef ScreenDllName
#define ScreenDllName "pdcurses.dll"
#endif
#endif

#ifndef BzipDllName
#define BzipDllName "libbz2.dll"
#endif

#ifndef ZlibDllName
#define ZlibDllName "zlib1.dll"
#endif

#ifndef BzipExeName
#define BzipExeName "bzip2.exe"
#endif

#ifndef GzipExeName
#define GzipExeName "gzip.exe"
#endif

#ifndef SetupBaseName
#define SetupBaseName "lynx"
#endif

#ifndef BinsSrcDir
#define BinsSrcDir GetEnv("LYNX_BINDIR")
#if BinsSrcDir == ""
#define BinsSrcDir "..\bin"
#endif
#endif

#ifndef DllsSrcDir
#define DllsSrcDir GetEnv("LYNX_DLLSDIR")
#if DllsSrcDir == ""
#define DllsSrcDir "..\bin"
#endif
#endif

#ifndef DocsSrcDir
#define DocsSrcDir GetEnv("LYNX_DOCSDIR")
#if DocsSrcDir == ""
#define DocsSrcDir "..\docs"
#endif
#endif

#ifndef HelpSrcDir
#define HelpSrcDir GetEnv("LYNX_HELPDIR")
#if HelpSrcDir == ""
#define HelpSrcDir "..\lynx_help"
#endif
#endif

[Setup]
AppName={#MyAppName}
#emit 'AppVersion=' + LYNX_VERSION
#emit 'VersionInfoDescription=Setup for "' + MyAppName + '"'
#define LYNX_TARGET0 StringChange(LYNX_VERSION,LYNX_RELEASE + "rel.",LYNX_RELEASE + ".00")
#define LYNX_TARGET1 StringChange(LYNX_TARGET0,LYNX_TARGETS + "dev.",LYNX_RELEASE + ".10")
#define LYNX_TARGET2 StringChange(LYNX_TARGET1,LYNX_TARGETS + "pre.",LYNX_RELEASE + ".20")
#emit 'VersionInfoVersion=' + LYNX_TARGET1
AppVerName={#MyAppVerName}
AppPublisher={#MyAppPublisher}
AppCopyright=� 1997-2021,2022, Thomas E. Dickey
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
LicenseFile=..\COPYHEADER
InfoBeforeFile=..\README
OutputDir=..\PACKAGE\lynx-setup
#emit 'OutputBaseFilename=' + SetupBaseName + LYNX_VERSION + '-setup'
Compression=lzma
SolidCompression=yes
PrivilegesRequired=none
SetupLogging=no

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Components]
Name: main; Description: The Lynx executable; types: full custom compact
Name: explorer; Description: Windows Explorer integration; types: full custom

[Tasks]
Name: for_all_users; Description: Install for all users on this machine; GroupDescription: Configuration Settings; Components: main; Check: isGuru; Flags: unchecked
Name: register_vars; Description: Use registry for environment variables; GroupDescription: Configuration Settings; Components: main; Flags: unchecked
Name: use_sendto; Description: Add Send To Entry; GroupDescription: Windows Explorer; Components: explorer; Flags: unchecked
Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Components: main; Flags: unchecked
Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; Components: main; Flags: unchecked


[Dirs]
Name: "{app}\doc"
Name: "{app}\doc\samples"
Name: "{app}\doc\test"
Name: "{app}\help"
Name: "{app}\help\keystrokes"
Name: "{app}\icon"

[Files]
#emit 'Source: "' + BinsSrcDir + '\' + SourceExeName + '"; DestDir: "{app}"; DestName: ' + MyAppExeName + '; AfterInstall: myPostExecutable; Flags: ignoreversion'
#ifndef NoScreenDll
#emit 'Source: "' + DllsSrcDir + '\' + ScreenDllName + '"; DestDir: "{app}"; DestName: ' + ScreenDllName + '; Flags: ignoreversion'
#endif
#emit 'Source: "' + DllsSrcDir + '\' + BzipExeName + '"; DestDir: "{app}"; DestName: ' + BzipExeName + '; Flags: ignoreversion'
#emit 'Source: "' + DllsSrcDir + '\' + GzipExeName + '"; DestDir: "{app}"; DestName: ' + GzipExeName + '; Flags: ignoreversion'
#emit 'Source: "' + DocsSrcDir + '\*.*"; DestDir: "{app}\doc"; Flags: '
#emit 'Source: "' + DocsSrcDir + '\..\samples\*.*"; DestDir: "{app}\doc\samples"; Flags: '
#emit 'Source: "' + DocsSrcDir + '\..\test\*.*"; DestDir: "{app}\doc\test"; Flags: '
#emit 'Source: "' + HelpSrcDir + '\*.*"; DestDir: "{app}\help"; Flags: '
#emit 'Source: "' + HelpSrcDir + '\keystrokes\*.*"; DestDir: "{app}\help\keystrokes"; Flags: '

; some of these data files are from an earlier installer by Claudio Santambrogio
Source: "..\lynx.cfg"; DestDir: "{app}" ; AfterInstall: myCustomCfg; Flags: ignoreversion
Source: "..\lynx.man"; DestDir: "{app}"
Source: "..\samples\*.lss"; DestDir: "{app}"
Source: "..\samples\home.htm"; DestDir: "{app}"
Source: "..\samples\jumps.htm"; DestDir: "{app}"
Source: "..\samples\lynx-demo.cfg"; DestDir: "{app}"
Source: "..\samples\lynx.bat"; DestDir: "{app}"
Source: "..\samples\lynx.ico"; DestDir: "{app}\icon"
Source: "..\samples\lynx_bookmarks.htm"; DestDir: "{app}"
Source: "..\samples\oldlynx.bat"; DestDir: "{app}"
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent

[UninstallDelete]
Type: files; Name: {app}\.lynx_cookies
Type: dirifempty; Name: {app}
#emit 'Type: files; Name: ' + mySendTo
#emit 'Type: files; Name: ' + myQuickLaunch

[Code]
#emit 'const MY_APP_NAME = ''{app}\' + myAppProg + '.exe'';'


function isGuru(): Boolean;
begin
    Result := isAdminLoggedOn();
end;

function environRootKey(): Integer;
begin
    Result := HKEY_CURRENT_USER;
end;

function appKey(): string;
begin
    Result := 'Software\Lynx';
end;

function envSubKey(): string;
begin
    Result := 'Environment';
end;

function appSubKey(): string;
begin
    Result := appKey() + '\' + envSubKey();
end;

function envSysKey(): string;
begin
    Result := 'System\CurrentControlSet\Control\Session Manager\Environment';
end;

// Set the environment variable ValueName.
procedure addVarToEnv(const RootKey: Integer; const SubKeyName, ValueName, toAdd: String);
var
    Updated : string;
begin
    Updated := ExpandConstant(toAdd);
    RegWriteStringValue(RootKey, SubKeyName, ValueName, Updated);
    Log('Added ' + toAdd + ' to ' + ValueName);
    // MsgBox('addVarToEnv: ' #13#13 + ValueName + '="' + Updated + '"', mbInformation, MB_OK)
end;

// Remove the given environment variable ValueName.
function removeVarFromEnv(const RootKey: Integer; const SubKeyName, ValueName: String): Boolean;
var
    Current : string;
begin
    Result := False;
    if RegQueryStringValue(RootKey, SubKeyName, ValueName, Current) then
    begin
        RegDeleteValue(RootKey, SubKeyName, ValueName);
        Result := True;
        Log('Removed ' + ValueName);
        // MsgBox('removeVarFromEnv: ' #13#13 + ValueName + '="' + Current + '"', mbInformation, MB_OK)
    end;
end;

function selectedVarsRootKey(): Integer;
begin
    if isTaskSelected('for_all_users') then
        Result := HKEY_LOCAL_MACHINE
    else
        Result := HKEY_CURRENT_USER;
end;

function selectedVarsSubKey(): String;
begin
    if isTaskSelected('for_all_users') then
    begin
        if isTaskSelected('register_vars') then
            Result := appSubKey()
        else
            Result := envSysKey();
    end else
    begin
        if isTaskSelected('register_vars') then
            Result := appSubKey()
        else
            Result := envSubKey();
    end;
end;

procedure addAnyVariable(const ValueName, newValue: String);
begin
    addVarToEnv(selectedVarsRootKey(), selectedVarsSubKey(), ValueName, NewValue);
end;

// FIXME: should only remove if it matches the installer's value
procedure removeAnyVariable(const ValueName: String);
begin
    removeVarFromEnv(HKEY_CURRENT_USER, envSubKey(), ValueName);
    removeVarFromEnv(HKEY_CURRENT_USER, appSubKey(), ValueName);
    removeVarFromEnv(HKEY_LOCAL_MACHINE, appSubKey(), ValueName);
    removeVarFromEnv(HKEY_LOCAL_MACHINE, envSysKey(), ValueName);
end;

// http://www.delphidabbler.com/articles?article=12
procedure AddSendTo();
begin
  CreateShellLink(
#emit 'ExpandConstant(''' + MySendTo + '''),'
#emit '''SendTo link for ' + myAppName + ''','
    ExpandConstant(MY_APP_NAME),      // program
    '',                               // option(s) will be followed by pathname
    '',                               // no target directory
    '',                               // no icon filename
    -1,                               // no icon index
    SW_SHOWNORMAL);
end;

procedure AddQuickLaunch();
begin
  CreateShellLink(
#emit 'ExpandConstant(''' + MyQuickLaunch + '''),'
#emit '''SendTo link for ' + myAppName + ''','
    ExpandConstant(MY_APP_NAME),      // program
    '',                               // option(s) will be followed by pathname
    '',                               // no target directory
    '',                               // no icon filename
    -1,                               // no icon index
    SW_SHOWNORMAL);
end;

// This is called after installing the executable.
procedure myPostExecutable();
var
  Keypath : String;
  AppDir  : String;
begin
  Keypath := appKey();
  AppDir := ExpandConstant('{app}');
  Log('Setting registry key "' + Keypath + '" to "' + AppDir + '"');
  if not RegWriteStringValue(selectedVarsRootKey(), Keypath, '', AppDir) then
    Log('Failed to set key');

  if isTaskSelected('use_sendto') then
    begin
    AddSendTo();
    Log('** added Send-To link');
    end;

  if isTaskSelected('quicklaunchicon') then
    begin
    AddQuickLaunch();
    Log('** added Quick-launch link');
    end;
end;

// This is called after installing the lynx.cfg file.
procedure myCustomCfg();
var
  AppDir  : String;
  CfgFile : String;
begin
  AppDir := ExpandConstant('{app}');
  CfgFile := AppDir + '\lynx.cfg';

  addAnyVariable('LYNX_CFG', CfgFile);
  Log('** set LYNX_CFG=' + CfgFile);

  SaveStringToFile(CfgFile, 'HELPFILE:' + AppDir + '/help/Lynx_help_main.html.gz' + #10, True);
  SaveStringToFile(CfgFile, 'COLOR_STYLE:' + AppDir + '/lynx.lss' + #10, True);

  SaveStringToFile(CfgFile, 'CHMOD_PATH:' + #10, True);
  SaveStringToFile(CfgFile, 'COPY_PATH:' + #10, True);
  SaveStringToFile(CfgFile, 'MKDIR_PATH:' + #10, True);
  SaveStringToFile(CfgFile, 'MV_PATH:' + #10, True);
  SaveStringToFile(CfgFile, 'RMDIR_PATH:' + #10, True);
  SaveStringToFile(CfgFile, 'RM_PATH:' + #10, True);
  SaveStringToFile(CfgFile, 'TOUCH_PATH:' + #10, True);

  Log('** customized ' + CfgFile);

  if isTaskSelected('use_sendto') then
    begin
    AddSendTo();
    Log('** added Send-To link');
    end;
end;

function CleanupMyKey(const theRootKey: Integer): Boolean;
var
  Path : String;
  Value : String;
begin
  Result := False;
  if RegQueryStringValue(theRootKey, appKey(), '', Value) then
    begin
      if Value <> '' then
        begin
        Result := True;
        Log('Deleting value of "' + appKey() + '" = "' + Value + '"');
        if not RegDeleteValue(theRootKey, appKey(), '') then
          Log('Failed to delete value');

        Path := appKey() + '\Environment';
        Log('Checking for subkey "' + Path + '"');
        if RegValueExists(theRootKey, Path, '') then
          begin
          if RegDeleteKeyIncludingSubkeys(theRootKey, Path) then
            Log('Deleted key "' + Path + '"')
          else
            Log('Failed to delete key "' + Path + '"');
          end;

        if RegDeleteKeyIfEmpty(theRootKey, appKey()) then
          Log('Deleted key "' + appKey() + '"')
        else
          Log('Failed to delete key "' + appKey() + '"');
        end
    end
end;

#ifdef SslGlob1
#emit "const SslGlob1 = " + SslGlob1 + ";"
#emit "const SslGlob2 = " + SslGlob2 + ";"
var
    SslDirPage     : TInputFileWizardPage;
    SslLibraryPath : String;

function DirContains(const PathList: string; const PathItem: string): Boolean;
var
    myList : string;
    myItem : string;
    myPart : string;
    offset : integer;
begin
    Result := False;
    myList := Uppercase(PathList);
    myItem := Uppercase(RemoveBackslashUnlessRoot(PathItem));
    offset := Pos(myItem, myList);
    if offset <> 0 then
        begin
        myPart := Copy( myList, offset + Length(myItem), Length(myList) );
        if ( Length(myPart) = 0 ) or ( Pos(';', myPart) = 1 ) or ( Pos('\;', myPart) = 1 ) then
            begin
            Result := True;
            end;
        end;
end;

function PathCat(const head, tail: string): string;
begin
    Result := RemoveBackslashUnlessRoot(head) + '\' + tail;
end;

procedure CopyFromTo(const source, target, name: string);
var
    FailExists : Boolean;
    Status:      Boolean;
begin
    Log('Copy from: ' + PathCat(source, name));
    Log('Copy   to: ' + PathCat(target, name));
    FailExists := False;
    Status := FileCopy(PathCat(source, name), PathCat(target, name), FailExists);
    if not Status then
        begin
        MsgBox('Failed to copy ' + name, mbError, MB_OK);
        Abort();
        end;
end;

procedure ReallyDelete(const fullPath: string);
begin
    if FileExists( fullpath ) then
        begin
        if DeleteFile( fullPath ) then
            Log( '...successful' )
        else
            begin
            MsgBox('Failed to delete ' + fullPath, mbError, MB_OK);
            end;
        end;
end;

procedure DeleteAppFile(const name: string);
var
    AppDir   : string;
    fullPath : string;
    findRec  : TFindRec;
begin
    AppDir := ExpandConstant('{app}');
    fullPath := PathCat( AppDir, name );
    Log( 'Deleting ' + fullPath );
    if Pos('*', fullPath) <> 0 then
        begin
        if FindFirst(fullPath, findRec) then
            begin
            ReallyDelete( PathCat( AppDir, findRec.name ) );
            while FindNext( findRec ) do
                ReallyDelete( PathCat( AppDir, findRec.name ) );
            end
        end
    else
        begin
        ReallyDelete( fullPath );
        end;
end;

function checkSslDir(): Boolean;
begin
    Result := True;
    SslLibraryPath := Trim( SslDirPage.Values[0] );
    if ( Length( SslLibraryPath ) = 0 ) or ( not FileExists( SslLibraryPath ) ) then
        begin
        MsgBox('No SSL library found', mbError, MB_OK)
        Result := False;
        end;
end;

procedure copySslDlls();
var
    SslDirectory   : String;
    SslFilename    : String;
    TargetDir      : String;
begin
    Log('Copying SSL DLLs');
    SslDirectory := ExtractFilePath(SslLibraryPath);

    // If the directory is not already in the PATH, copy the DLLs to
    // the application directory.
    if DirContains( GetEnv('PATH'), SslDirectory) then
        Log( 'PATH contains SSL directory' )
    else
        begin
        TargetDir := ExpandConstant('{app}');
        CreateDir(TargetDir);
        if DirExists(TargetDir) then
            begin
            SslFilename := Lowercase( ExtractFileName( SslLibraryPath ) );
            CopyFromTo( SslDirectory, TargetDir, SslFilename );
            Log( 'comparing: ' + SslFilename + ' to ' + SslGlob1 );
            if CompareText( SslFilename, SslGlob1 ) = 0 then
                // old-ssl is literal, new is a glob...
                CopyFromTo( SslDirectory, TargetDir, SslGlob2 )
            else
                // new-ssl matches "libssl-x-x-z", s/libssl/libcrypto/
                SslFilename := 'libcrypto' + Copy(SslFilename, 7, Length(SslFilename));
                CopyFromTo( SslDirectory, TargetDir, SslFilename );
#ifdef RuntimeBundle
            // older releases of OpenSSL bundled the Visual Studio runtime
            SslFilename := SslDirectory + '\' + 'msvcr120.dll' ;
            if FileExists(SslFilename) then
                begin
                CopyFromTo( SslDirectory, TargetDir, 'msvcr120.dll' );
                end
#endif
            end
        else
            begin
            MsgBox( 'Cannot create application directory', mbError, MB_OK )
            Abort();
            end
        end;
    Log('done - Copying SSL DLLs');
end;

procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
    SetPreviousData( PreviousDataKey, 'SSL PATH', SslLibraryPath );
end;

function NextButtonClick(CurPageId: integer): Boolean;
begin
    Result := True;
    if CurPageId = SslDirPage.Id then
        begin
        Result := checkSslDir();
        end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
    if CurStep = ssInstall then
    begin
        CopySslDlls();
    end;
end;

procedure InitializeWizard();
var
    myGlob: string;
begin
    // Create a page to locate the SSL library
    SslDirPage := CreateInputFilePage(wpSelectDir,
        'Select SSL Library Location',
        'Where is the SSL library located?',
        'Select it from the directory, then click Next.');

    myGlob := 'SSL dll|' + SslGlob1;
    Log( 'search for SSL libraries ' + myGlob );
    SslDirPage.Add( 'Locate SSL library:', myGlob, '*.dll' );
    SslDirPage.Values[0] := GetPreviousData( 'SSL PATH', '' );
end;
#endif

// On uninstall, we do not know which registry setting was selected during install, so we remove all.
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  case CurUninstallStep of
    usUninstall:
      begin
      Log('CurUninstallStepChanged:' + 'Uninstall is about to start.')
        // ...insert code to perform pre-uninstall tasks here...
#ifdef SslGlob1
      DeleteAppFile( SslGlob1 );
      DeleteAppFile( SslGlob2 );
      DeleteAppFile( 'msvcr120.dll' );
#endif
      end;
    usPostUninstall:
      begin
        removeAnyVariable('LYNX_CFG');
      {
        If we don't find the settings in the current user, try the local machine.
        The setup program cannot pass the all-users flag to the uninstaller, so we
        have to try both.
      }
      Log('Checking current-user registry key');
      if not CleanupMyKey(HKEY_CURRENT_USER) then
        begin
        Log('Checking local-machine registry key');
        CleanupMyKey(HKEY_LOCAL_MACHINE);
        end;

        Log('CurUninstallStepChanged:' + 'Uninstall just finished.');
      end;
  end;
end;