fpc/installer/install.pas
2020-05-03 21:42:20 +00:00

2063 lines
59 KiB
ObjectPascal

{
This file is part of the Free Pascal run time library.
Copyright (c) 1993-2015 by Florian Klaempfl
member of the Free Pascal development team
This is the install program for the DOS and OS/2 versions of Free Pascal
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
program install;
{ $DEFINE DLL} (* TH - if defined, UNZIP32.DLL library is used to unpack. *)
{ $DEFINE DOSSTUB} (* TH - should _not_ be defined unless creating a bound DOS and OS/2 installer!!! *)
(* Defining DOSSTUB causes adding a small piece of code *)
(* for starting the OS/2 part from the DOS part of a bound *)
(* application if running in OS/2 VDM (DOS) window. Used *)
(* only if compiling with TP/BP (see conditionals below). *)
{$IFDEF OS2}
{$DEFINE DLL}
{$ENDIF DLL}
{$IFDEF VER60}
{$DEFINE TP}
{$ENDIF}
{$IFDEF VER70}
{$DEFINE TP}
{$ENDIF}
{$IFNDEF TP}
{$UNDEF DOSSTUB}
{$ELSE}
{$IFDEF OS2}
{$UNDEF DOSSTUB}
{$ENDIF}
{$ENDIF}
{$IFDEF DPMI}
{$UNDEF DOSSTUB}
{$ENDIF}
{$ifdef go32v2}
{$define MAYBE_LFN}
{$endif}
{$ifdef debug}
{$ifdef win32}
{$define MAYBE_LFN}
{$endif win32}
{$endif debug}
{$ifdef TP}
{$define MAYBE_LFN}
{$endif}
uses
{$IFDEF OS2}
{$IFDEF FPC}
DosCalls,
{$ELSE FPC}
{$IFDEF VirtualPascal}
OS2Base,
{$ELSE VirtualPascal}
BseDos,
{$ENDIF VirtualPascal}
{$ENDIF FPC}
{$ENDIF OS2}
{$IFDEF GO32V2}
emu387,
{$ENDIF}
{$ifdef HEAPTRC}
heaptrc,
{$endif HEAPTRC}
strings,dos,objects,drivers,
{$IFNDEF FVISION}
commands,
HelpCtx,
{$ENDIF}
unzip51g,ziptypes,
{$IFDEF DLL}
unzipdll,
{$ENDIF}
app,dialogs,views,menus,msgbox,colortxt,tabs,scroll,
WHTMLScn,insthelp;
const
installerversion='3.3.1';
installercopyright='Copyright (c) 1993-2018 Florian Klaempfl';
maxpacks=20;
maxpackages=32;
maxdefcfgs=1024;
HTMLIndexExt = '.htx';
CfgExt = '.dat';
MaxStatusPos = 4;
StatusChars: string [MaxStatusPos] = '/-\|';
StatusPos: byte = 1;
{ this variable is set to true if an ide is installed }
haside : boolean = false;
hashtmlhelp : boolean = false;
{$ifdef Unix}
DirSep='/';
{$else}
DirSep='\';
{$endif}
type
tpackage=record
name : string[60];
zip : string[40]; { default zipname }
zipshort : string[12]; { 8.3 zipname }
diskspace : int64; { diskspace required }
end;
tpack=record
name : string[12];
binsub : string[40];
ppc386 : string[20];
targetname : string[40];
defidecfgfile,
defideinifile,
defcfgfile,
setpathfile : string[12];
include : boolean;
{ filechk : string[40]; Obsolete }
packages : longint;
package : array[1..maxpackages] of tpackage;
end;
tcfgarray = array[1..maxdefcfgs] of pstring;
cfgrec=record
title : string[80];
version : string[20];
helpidx,
docsub,
basepath : DirStr;
packs : word;
pack : array[1..maxpacks] of tpack;
defideinis,
defidecfgs,
defcfgs,
defsetpaths : longint;
defideini,
defidecfg,
defcfg,
defsetpath : tcfgarray;
end;
datarec=record
basepath : DirStr;
cfgval : word;
packmask : array[1..maxpacks] of sw_word;
end;
punzipdialog=^tunzipdialog;
tunzipdialog=object(tdialog)
filetext : pstatictext;
extractfiletext : pstatictext;
currentfile : string;
constructor Init(var Bounds: TRect; ATitle: TTitleStr);
procedure do_unzip(s,topath:string);
end;
penddialog = ^tenddialog;
tenddialog = object(tdialog)
constructor init;
end;
pinstalldialog = ^tinstalldialog;
tinstalldialog = object(tdialog)
constructor init;
procedure handleevent(var event : tevent);virtual;
end;
PFPHTMLFileLinkScanner = ^TFPHTMLFileLinkScanner;
TFPHTMLFileLinkScanner = object(THTMLFileLinkScanner)
function CheckURL(const URL: string): boolean; virtual;
function CheckText(const Text: string): boolean; virtual;
procedure ProcessDoc(Doc: PHTMLLinkScanFile); virtual;
end;
phtmlindexdialog = ^thtmlindexdialog;
thtmlindexdialog = object(tdialog)
text : pstatictext;
constructor init(var Bounds: TRect; ATitle: TTitleStr);
end;
tapp = object(tapplication)
procedure initmenubar;virtual;
procedure initstatusline;virtual;
procedure handleevent(var event : tevent);virtual;
procedure do_installdialog;
procedure readcfg(const fn:string);
procedure checkavailpack;
end;
PSpecialInputLine= ^TSpecialInputLine;
TSpecialInputLine = object (TInputLine)
procedure GetData(var Rec); virtual;
end;
{$IFDEF DOSSTUB}
PByte = ^byte;
PRunBlock = ^TRunBlock;
TRunBlock = record
Length: word;
Dependent: word;
Background: word;
TraceLevel: word;
PrgTitle: PChar;
PrgName: PChar;
Args: PChar;
TermQ: longint;
Environment: pointer;
Inheritance: word;
SesType: word;
Icon: pointer;
PgmHandle: longint;
PgmControl: word;
Column: word;
Row: word;
Width: word;
Height: word;
end;
{$ENDIF}
var
installapp : tapp;
startpath : string;
successfull : boolean;
cfg : cfgrec;
data : datarec;
CfgName: NameStr;
DStr: DirStr;
EStr: ExtStr;
UnzDlg : punzipdialog;
log : text;
createlog : boolean;
{$IFNDEF DLL}
const
UnzipErr: longint = 0;
{$ENDIF}
{$ifdef MAYBE_LFN}
const
locallfnsupport : boolean = false;
{$endif MAYBE_LFN}
{*****************************************************************************
Helpers
*****************************************************************************}
procedure errorhalt;
begin
installapp.done;
if CreateLog then
begin
WriteLn (Log, 'Installation hasn''t been completed.');
Close (Log);
end;
halt(1);
end;
procedure WriteLog (const S: string);
begin
if CreateLog then
begin
WriteLn (Log, S);
Flush (Log);
end;
end;
function packagemask(i:longint):longint;
begin
packagemask:=1 shl (i-1);
end;
function upper(const s : string):string;
var
i : integer;
begin
for i:=1 to length(s) do
if s[i] in ['a'..'z'] then
upper[i]:=chr(ord(s[i])-32)
else
upper[i]:=s[i];
upper[0]:=s[0];
end;
procedure Replace(var s:string;const s1,s2:string);
var
i : longint;
begin
repeat
i:=pos(s1,s);
if i>0 then
begin
Delete(s,i,length(s1));
Insert(s2,s,i);
end;
until i=0;
end;
function DotStr(l:longint):string;
var
TmpStr : string[32];
i : longint;
begin
Str(l,TmpStr);
i:=Length(TmpStr);
while (i>3) do
begin
i:=i-3;
if TmpStr[i]<>'-' then
Insert('.',TmpStr,i+1);
end;
DotStr:=TmpStr;
end;
function file_exists(const f : string;const path : string) : boolean;
begin
file_exists:=fsearch(f,path)<>'';
end;
function createdir(s:string):boolean;
var
s1,start : string;
err : boolean;
i : longint;
begin
err:=false;
{$I-}
getdir(0,start);
{$ifndef Unix}
if (s[2]=':') and (s[3]=DirSep) then
begin
chdir(Copy(s,1,3));
Delete(S,1,3);
end;
{$endif}
repeat
i:=Pos(DirSep,s);
if i=0 then
i:=255;
s1:=Copy(s,1,i-1);
Delete(s,1,i);
ChDir(s1);
if ioresult<>0 then
begin
mkdir(s1);
chdir(s1);
if ioresult<>0 then
begin
err:=true;
break;
end;
end;
until s='';
chdir(start);
{$I+}
createdir:=err;
end;
function DiskSpaceN(const zipfile : string) : longint;
var
compressed,uncompressed : longint;
s : string;
begin
s:=zipfile+#0;
if not (IsZip (@S [1])) then
DiskSpaceN := -1
else
begin
Uncompressed:=UnzipSize(@s[1],compressed);
DiskSpaceN:=uncompressed shr 10;
end;
end;
function diskspacestr(uncompressed : longint) : string;
begin
if Uncompressed = -1 then
DiskSpacestr := ' [INVALID]'
else
diskspacestr:=' ('+DotStr(uncompressed)+' KB)';
end;
function createinstalldir(s : string) : boolean;
var
err : boolean;
dir : searchrec;
params : array[0..0] of pointer;
begin
if s[length(s)]=DirSep then
dec(s[0]);
FindFirst(s,AnyFile,dir);
if doserror=0 then
begin
if Dir.Attr and Directory = 0 then
begin
messagebox('A file with the name chosen as the installation '+
'directory exists already. Cannot create this directory!',nil,
mferror+mfokbutton);
createinstalldir:=false;
end else
createinstalldir:=messagebox('The installation directory exists already. '+
'Do you want to continue ?',nil,
mferror+mfyesbutton+mfnobutton)=cmYes;
exit;
end;
err:=Createdir(s);
if err then
begin
params[0]:=@s;
messagebox('The installation directory %s couldn''t be created',
@params,mferror+mfokbutton);
createinstalldir:=false;
exit;
end;
{$ifndef TP}
{$IFNDEF OS2}
FindClose (dir);
{$ENDIF}
{$endif}
createinstalldir:=true;
end;
function GetProgDir: DirStr;
var
D: DirStr;
N: NameStr;
E: ExtStr;
begin
FSplit (FExpand (ParamStr (0)), D, N, E);
if (D [0] <> #0) and (D [byte (D [0])] = '\') then Dec (D [0]);
GetProgDir := D;
end;
function GetZipErrorInfo(error : longint) : string;
var
ErrorStr : string;
begin
case error of
unzip_CRCErr : GetZipErrorInfo:='CRC error';
unzip_WriteErr : GetZipErrorInfo:='Write error';
unzip_ReadErr : GetZipErrorInfo:='Read error';
unzip_ZipFileErr : GetZipErrorInfo:='ZipFile erroe';
unzip_UserAbort : GetZipErrorInfo:='User abort';
unzip_NotSupported : GetZipErrorInfo:='Not supported';
unzip_Encrypted : GetZipErrorInfo:='File is encrypted';
unzip_InUse : GetZipErrorInfo:='Fie is in use';
unzip_InternalError : GetZipErrorInfo:='Internal error'; {Error in zip format}
unzip_NoMoreItems : GetZipErrorInfo:='No more items';
unzip_FileError : GetZipErrorInfo:='File error'; {Error Accessing file}
unzip_NotZipfile : GetZipErrorInfo:='Not a zipfile'; {not a zip file}
unzip_SeriousError : GetZipErrorInfo:='Serious error'; {serious error}
unzip_MissingParameter : GetZipErrorInfo:='Missing parameter'; {missing parameter}
else
begin
Str(Error,ErrorStr);
GetZipErrorInfo:='Unknown error '+errorstr;
end;
end;
end;
{*****************************************************************************
HTML-Index Generation
*****************************************************************************}
var
indexdlg : phtmlindexdialog;
constructor thtmlindexdialog.Init(var Bounds: TRect; ATitle: TTitleStr);
var
r : trect;
begin
inherited init(bounds,atitle);
Options:=Options or ofCentered;
R.Assign (4, 2,bounds.B.X-Bounds.A.X-2, 4);
text:=new(pstatictext,init(r,'Please wait ...'));
insert(text);
end;
procedure TFPHTMLFileLinkScanner.ProcessDoc(Doc: PHTMLLinkScanFile);
var
oldtext : pstring;
begin
oldtext:=indexdlg^.text^.text;
indexdlg^.text^.text:=newstr('Processing '+Doc^.GetDocumentURL);
indexdlg^.text^.drawview;
inherited ProcessDoc(Doc);
disposestr(indexdlg^.text^.text);
indexdlg^.text^.text:=oldtext;
indexdlg^.text^.drawview;
end;
function TFPHTMLFileLinkScanner.CheckURL(const URL: string): boolean;
var OK: boolean;
const HTTPPrefix = 'http:';
FTPPrefix = 'ftp:';
begin
OK:=inherited CheckURL(URL);
if OK then OK:=DirAndNameOf(URL)<>'';
if OK then OK:=CompareText(copy(ExtOf(URL),1,4),'.HTM')=0;
if OK then OK:=CompareText(copy(URL,1,length(HTTPPrefix)),HTTPPrefix)<>0;
if OK then OK:=CompareText(copy(URL,1,length(FTPPrefix)),FTPPrefix)<>0;
CheckURL:=OK;
end;
function TFPHTMLFileLinkScanner.CheckText(const Text: string): boolean;
var OK: boolean;
S: string;
begin
S:=Trim(Text);
OK:=(S<>'') and (copy(S,1,1)<>'[');
CheckText:=OK;
end;
procedure writehlpindex(filename : string);
var
LS : PFPHTMLFileLinkScanner;
BS : PBufStream;
Re : Word;
params : array[0..0] of pointer;
dir : searchrec;
r : trect;
begin
r.assign(10,10,70,15);
indexdlg:=new(phtmlindexdialog,init(r,'Creating HTML index file, please wait ...'));
desktop^.insert(indexdlg);
{ warning FIXME !!!!, don't know what is to fix here ... PM }
New(LS, Init(DirOf(FileName)));
LS^.ProcessDocument(FileName,[soSubDocsOnly]);
if LS^.GetDocumentCount=0 then
begin
params[0]:=@filename;
MessageBox('Problem creating help index %1, aborting',@params,
mferror+mfokbutton);
end
else
begin
FileName:=DirAndNameOf(FileName)+HTMLIndexExt;
findfirst(filename,AnyFile,dir);
if doserror=0 then
begin
params[0]:=@filename;
Re:=MessageBox('Help index %s already exists, overwrite it?',@params,
mfinformation+mfyesbutton+mfnobutton);
end
else
Re:=cmYes;
if Re<>cmNo then
begin
New(BS, Init(FileName, stCreate, 4096));
if Assigned(BS)=false then
begin
MessageBox('Error while writing help index! '+
'No help index is created',@params,
mferror+mfokbutton);
Re:=cmCancel;
end
else
begin
LS^.StoreDocuments(BS^);
if BS^.Status<>stOK then
begin
MessageBox('Error while writing help index!'#13+
'No help index is created',@params,
mferror+mfokbutton);
Re:=cmCancel;
end;
Dispose(BS, Done);
end;
end;
end;
Dispose(LS, Done);
desktop^.delete(indexdlg);
dispose(indexdlg,done);
end;
{*****************************************************************************
Writing of fpc.cfg
*****************************************************************************}
procedure writedefcfg(const fn:string;const cfgdata : tcfgarray;count : longint;const targetname : string);
var
t : text;
i : longint;
s : string;
dir : searchrec;
params : array[0..0] of pointer;
d : dirstr;
n : namestr;
e : extstr;
begin
{ already exists }
findfirst(fn,AnyFile,dir);
if doserror=0 then
begin
params[0]:=@fn;
if MessageBox('Config %s already exists, continue writing default config?',@params,
mfinformation+mfyesbutton+mfnobutton)=cmNo then
exit;
end;
{ create directory }
fsplit(fn,d,n,e);
createdir(d);
{ create the fpc.cfg }
assign(t,fn);
{$I-}
rewrite(t);
{$I+}
if ioresult<>0 then
begin
params[0]:=@fn;
MessageBox(#3'A config not written.'#13#3'%s'#13#3'couldn''t be created',@params,mfinformation+mfokbutton);
exit;
end;
for i:=1 to count do
if assigned(cfgdata[i]) then
begin
s:=cfgdata[i]^;
Replace(s,'%basepath%',data.basepath);
Replace(s,'%targetname%',targetname);
if pos('-',targetname)=0 then
begin
Replace(s,'%targetos%',targetname);
Replace(s,'%fpctargetmacro%','$FPCOS')
end
else
begin
Replace(s,'%targetos%',Copy(targetname,pos('-',targetname)+1,255));
Replace(s,'%fpctargetmacro%','$FPCTARGET');
end;
writeln(t,s);
end
else
writeln(t,'');
close(t);
end;
{*****************************************************************************
TUnZipDialog
*****************************************************************************}
constructor tunzipdialog.Init(var Bounds: TRect; ATitle: TTitleStr);
var
r : trect;
begin
inherited init(bounds,atitle);
Options:=Options or ofCentered;
(* R.Assign (11, 4, 38, 6);*)
R.Assign (1, 4,bounds.B.X-Bounds.A.X-2, 6);
filetext:=new(pstatictext,init(r,#3'File: '));
insert(filetext);
R.Assign (1, 7,bounds.B.X-Bounds.A.X-2, 9);
extractfiletext:=new(pstatictext,init(r,#3' '));
insert(extractfiletext);
end;
{$IFNDEF DLL}
procedure UnzipCheckFn (Retcode: longint; Rec: pReportRec );{$ifdef Delphi32}STDCALL;{$endif}
{$ifndef fpc}{$IFNDEF BIT32} FAR;{$ENDIF BIT32}{$endif}
var
name : string;
begin
case Rec^.Status of
unzip_starting:
UnzipErr := 0;
file_starting:
begin
with UnzDlg^.extractfiletext^ do
begin
Disposestr(text);
name:=Strpas(Rec^.FileName);
UnzDlg^.currentfile:=name;
Text:=NewStr(#3+name);
DrawView;
end;
end;
file_failure:
UnzipErr := RetCode;
file_unzipping:
begin
with UnzDlg^.FileText^ do
begin
Inc (StatusPos);
if StatusPos > MaxStatusPos then StatusPos := 1;
Text^ [Length (Text^)] := StatusChars [StatusPos];
DrawView;
end;
end;
end;
end;
{$ENDIF}
procedure tunzipdialog.do_unzip(s,topath : string);
var
{$ifdef MAYBE_LFN}
p : pathstr;
n : namestr;
e : extstr;
islfn : boolean;
{$endif MAYBE_LFN}
again : boolean;
st2,fn,dir,wild : string;
begin
Disposestr(filetext^.text);
filetext^.Text:=NewStr(#3'File: '+s + #13#3' ');
filetext^.drawview;
if not(file_exists(s,startpath)) then
begin
messagebox('File "'+s+'" missing for the selected installation. '+
'Installation hasn''t been completed.',nil,mferror+mfokbutton);
WriteLog ('File "' + S +
'" missing for the selected installation!');
errorhalt;
end;
{$IFNDEF DLL}
{$IFDEF FPC}
SetUnzipReportProc (@UnzipCheckFn);
{$ELSE FPC}
SetUnzipReportProc (UnzipCheckFn);
{$ENDIF FPC}
{$ENDIF DLL}
WriteLog ('Unpacking ' + AllFiles + ' from '
+ StartPath + DirSep + S + ' to ' + ToPath);
repeat
fn:=startpath+DirSep+s+#0;
dir:=topath+#0;
wild:=AllFiles + #0;
again:=false;
FileUnzipEx(@fn[1],@dir[1],@wild[1]);
if (UnzipErr <> 0) and (UnzipErr <> 1) then
begin
if CreateLog then
begin
WriteLn (Log, 'Error ', UnzipErr, ' while unpacking!');
Flush (Log);
end;
s:=GetZipErrorInfo(UnzipErr);
{ Str(UnzipErr,s);}
st2:='';
if UnzipErr=unzip_WriteErr then
begin
{$ifdef MAYBE_LFN}
if not(locallfnsupport) then
begin
islfn:=false;
fsplit(currentfile,p,n,e);
if (length(n)>8) or (length(e)>4) or
(pos('.',n)>0) or (upper(p+n+e)<>upper(currentfile)) then
islfn:=true;
if islfn then
begin
WriteLog ('Error while extracting ' +
CurrentFile + ' because of missing LFN support,' +
LineEnding + ' skipping rest of ZIP file.');
messagebox('Error while extracting '+currentfile+
#13#3'because of missing lfn support'+
#13#3'skipping rest of zipfile '+s
,nil,mferror+mfOkButton);
again:=false;
exit;
end;
end
else
{$endif MAYBE_LFN}
st2:=' Disk full?';
end;
if CreateLog then
WriteLog ('Error (' + S + ') while extracting.' + ST2);
if messagebox('Error (' + S + ') while extracting.'+st2+#13+
#13#3'Try again?',nil,mferror+mfyesbutton+mfnobutton)=cmYes then
again:=true
else
errorhalt;
end;
until not again;
end;
{*****************************************************************************
TEndDialog
*****************************************************************************}
constructor tenddialog.init;
var
R : TRect;
P : PStaticText;
Control : PButton;
YB: word;
{$IFNDEF UNIX}
i : longint;
S: string;
WPath: boolean;
MixedCasePath: boolean;
{$ENDIF}
{$IFDEF OS2}
ErrPath: array [0..259] of char;
Handle: longint;
WLibPath: boolean;
const
EMXName: array [1..4] of char = 'EMX'#0;
BFD2EName: array [1..6] of char = 'BFD2E'#0;
{$ENDIF}
begin
if haside then
YB := 15
else
YB := 14;
{$IFNDEF UNIX}
s:='';
for i:=1 to cfg.packs do
if cfg.pack[i].binsub<>'' then
begin
if s<>'' then
s:=s+';';
S := s+Data.BasePath + Cfg.pack[i].BinSub;
end;
if Pos (Upper (S), Upper (GetEnv ('PATH'))) = 0 then
begin
WPath := true;
Inc (YB, 3);
end
else
WPath := false;
{ look if path is set as Path,
this leads to problems for mingw32 make PM }
MixedCasePath:=false;
for i:=1 to EnvCount do
begin
if Pos('PATH=',Upper(EnvStr(i)))=1 then
if Pos('PATH=',EnvStr(i))<>1 then
Begin
MixedCasePath:=true;
Inc(YB, 2);
End;
end;
{$IFDEF OS2}
if DosLoadModule (@ErrPath, SizeOf (ErrPath), @EMXName, Handle) = 0 then
begin
WLibPath := false;
DosFreeModule (Handle);
if DosLoadModule (@ErrPath, SizeOf (ErrPath), @BFD2EName, Handle) = 0 then
begin
WLibPath := false;
DosFreeModule (Handle);
end
else
begin
WLibPath := true;
Inc (YB, 2);
end;
end
else
begin
WLibPath := true;
Inc (YB, 2);
end;
{$ENDIF}
{$ENDIF}
R.Assign(6, 6, 74, YB);
inherited init(r,'Installation successful.');
Options:=Options or ofCentered;
{$IFNDEF UNIX}
if WPath then
begin
R.Assign(2, 3, 64, 5);
P:=new(pstatictext,init(r,'Extend your PATH variable with '''+S+''''));
insert(P);
end;
{$IFDEF OS2}
if WLibPath then
begin
if WPath then
S := 'and your LIBPATH with ''' + S
else
S := 'Extend your LIBPATH with ''' + S;
System.Delete (S, Length (S) - 6, 7);
S := S + 'dll''';
R.Assign (2, YB - 15, 64, YB - 13);
P := New (PStaticText, Init (R, S));
Insert (P);
end;
{$ELSE OS2}
if MixedCasePath then
begin
R.Assign(2, 5, 64, 6);
P:=new(pstatictext,init(r,'You need to use setpath.bat file if you want to use Makefiles'));
insert(P);
end;
{$ENDIF OS2}
{$ENDIF}
R.Assign(2, YB - 13, 64, YB - 12);
P:=new(pstatictext,init(r,'To compile files enter ''fpc [file]'''));
insert(P);
if haside then
begin
R.Assign(2, YB - 12, 64, YB - 10);
P:=new(pstatictext,init(r,'To start the IDE (Integrated Development Environment) type ''fp'' at a command line prompt'));
insert(P);
end;
R.Assign (29, YB - 9, 39, YB - 7);
Control := New (PButton, Init (R,'~O~k', cmOK, bfDefault));
Insert (Control);
end;
{*****************************************************************************
TInstallDialog
*****************************************************************************}
{$ifdef MAYBE_LFN}
var
islfn : boolean;
procedure lfnreport( Retcode : longint;Rec : pReportRec );
var
p : pathstr;
n : namestr;
e : extstr;
begin
fsplit(strpas(rec^.Filename),p,n,e);
if (length(n)>8) or (length(e)>4) or
(pos('.',n)>0) or (upper(p+n+e)<>upper(strpas(rec^.Filename))) then
islfn:=true;
end;
function haslfn(const zipfile : string) : boolean;
var
buf : array[0..255] of char;
begin
strpcopy(buf,zipfile);
islfn:=false;
{$ifdef FPC}
ViewZip(buf,AllFiles,@lfnreport);
{$else FPC}
ViewZip(buf,AllFiles,lfnreport);
{$endif FPC}
haslfn:=islfn;
end;
{$endif MAYBE_LFN}
var
AllFilesPresent : boolean;
procedure presentreport( Retcode : longint;Rec : pReportRec );
var
st : string;
f : file;
size,time : longint;
p : pathstr;
n : namestr;
e : extstr;
begin
if not ALLFilesPresent then
exit;
st:=Data.BasePath+strpas(rec^.Filename);
fsplit(st,p,n,e);
if not file_exists(n+e,p) then
AllFilesPresent:=false
else
begin
Assign(f,st);
Reset(f,1);
if IOresult<>0 then
begin
ALLfilesPresent:=false;
exit;
end;
GetFtime(f,time);
size:=FileSize(f);
if (rec^.Time<>time) or (rec^.size<>size) then
ALLFilesPresent:=false;
close(f);
end;
end;
function AreAllFilesPresent(const zipfile : string) : boolean;
var
buf : array[0..255] of char;
begin
strpcopy(buf,zipfile);
AllFilesPresent:=true;
{$ifdef FPC}
ViewZip(buf,AllFiles,@presentreport);
{$else FPC}
ViewZip(buf,AllFiles,presentreport);
{$endif FPC}
AreAllFilesPresent:=AllFilesPresent;
end;
constructor tinstalldialog.init;
const
width = 76;
height = 20;
x1 = (79-width) div 2;
y1 = (23-height) div 2;
x2 = x1+width;
y2 = y1+height;
var
tabr,tabir,r : trect;
packmask : array[1..maxpacks] of longint;
enabmask : array[1..maxpacks] of longint;
i,line,j : integer;
items : array[1..maxpacks] of psitem;
f : pview;
found : boolean;
okbut,cancelbut : pbutton;
firstitem : array[1..maxpacks] of integer;
packcbs : array[1..maxpacks] of pcheckboxes;
packtd : ptabdef;
labpath : plabel;
ilpath : pspecialinputline;
tab : ptab;
titletext : pcoloredtext;
labcfg : plabel;
cfgcb : pcheckboxes;
scrollbox: pscrollbox;
sbr,sbsbr: trect;
sbsb: pscrollbar;
zipfile : string;
begin
f:=nil;
{ walk packages reverse and insert a newsitem for each, and set the mask }
for j:=1 to cfg.packs do
with cfg.pack[j] do
begin
firstitem[j]:=0;
items[j]:=nil;
packmask[j]:=0;
enabmask[j]:=0;
for i:=packages downto 1 do
begin
zipfile:='';
if file_exists(package[i].zip,startpath) then
zipfile:=startpath+DirSep+package[i].zip
else if file_exists(package[i].zipshort,startpath) then
begin
zipfile:=startpath+DirSep+package[i].zipshort;
{ update package to replace the full zipname with the short name }
package[i].zip:=package[i].zipshort;
end;
if zipfile<>'' then
begin
{ get diskspace required }
package[i].diskspace:=diskspaceN(zipfile);
{$ifdef MAYBE_LFN}
if not(locallfnsupport) then
begin
if not(haslfn(zipfile)) then
begin
items[j]:=newsitem(package[i].name+diskspacestr(package[i].diskspace),items[j]);
packmask[j]:=packmask[j] or packagemask(i);
enabmask[j]:=enabmask[j] or packagemask(i);
firstitem[j]:=i-1;
WriteLog ('Checking lfn usage for ' + zipfile + ' ... no lfn');
end
else
begin
items[j]:=newsitem(package[i].name+' (requires LFN support)',items[j]);
enabmask[j]:=enabmask[j] or packagemask(i);
firstitem[j]:=i-1;
WriteLog ('Checking lfn usage for ' + zipfile + ' ... uses lfn');
end;
end
else
{$endif MAYBE_LFN}
begin
items[j]:=newsitem(package[i].name+diskspacestr(package[i].diskspace)
{$ifdef DEBUG}
+' ('+dotstr(i)+')'
{$endif DEBUG}
,items[j]);
packmask[j]:=packmask[j] or packagemask(i);
enabmask[j]:=enabmask[j] or packagemask(i);
firstitem[j]:=i-1;
end;
end
else
items[j]:=newsitem(package[i].name
{$ifdef DEBUG}
+' ('+dotstr(i)+')'
{$endif DEBUG}
,items[j]);
end;
end;
{ If no component found abort }
found:=false;
for j:=1 to cfg.packs do
if packmask[j]<>0 then
found:=true;
if not found then
begin
messagebox('No components found to install, aborting.',nil,mferror+mfokbutton);
if CreateLog then
WriteLog ('No components found to install, aborting.');
errorhalt;
end;
r.assign(x1,y1,x2,y2);
inherited init(r,'');
Options:=Options or ofCentered;
GetExtent(R);
R.Grow(-2,-1);
Dec(R.B.Y,2);
TabR.Copy(R);
TabIR.Copy(R);
TabIR.Grow(-2,-2);
TabIR.Move(-2,0);
{-------- General Sheets ----------}
R.Copy(TabIR);
r.move(0,1);
r.b.x:=r.a.x+40;
r.b.y:=r.a.y+1;
new(titletext,init(r,cfg.title,$71));
r.move(0,2);
r.b.x:=r.a.x+40;
new(labpath,init(r,'~B~ase path',f));
r.move(0,1);
r.b.x:=r.a.x+40;
r.b.y:=r.a.y+1;
new(ilpath,init(r,high(DirStr)));
r.move(0,2);
r.b.x:=r.a.x+40;
new(labcfg,init(r,'Con~f~ig',f));
r.move(0,1);
r.b.x:=r.a.x+40;
r.b.y:=r.a.y+1;
new(cfgcb,init(r,newsitem('create fpc.cfg',nil)));
data.cfgval:=1;
{-------- Pack Sheets ----------}
for j:=1 to cfg.packs do
begin
R.Copy(TabIR);
if R.A.Y+cfg.pack[j].packages>R.B.Y then
R.B.Y:=R.A.Y+cfg.pack[j].packages;
new(packcbs[j],init(r,items[j]));
if data.packmask[j]=high(sw_word) then
data.packmask[j]:=packmask[j];
packcbs[j]^.enablemask:={$ifdef DEV}$7fffffff{$else}enabmask[j]{$endif};
packcbs[j]^.sel:=firstitem[j];
end;
{--------- Main ---------}
packtd:=nil;
sbr.assign(1,3,tabr.b.x-tabr.a.x-3,tabr.b.y-tabr.a.y-1);
for j:=cfg.packs downto 1 do
begin
if (sbr.b.y-sbr.a.y)<cfg.pack[j].packages then
begin
sbsbr.assign(sbr.b.x,sbr.a.y,sbr.b.x+1,sbr.b.y);
sbsb:=CreateIdScrollBar (sbsbr.a.x, sbsbr.a.y,sbsbr.b.y-sbsbr.a.y,j,false);
sbsb^.SetRange(0,cfg.pack[j].packages-(sbsbr.b.y-sbsbr.a.y)-1);
sbsb^.SetStep(5,1);
//New(sbsb, init(sbsbr));
end
else
sbsb:=nil;
New(ScrollBox, Init(sbr, nil, sbsb));
PackCbs[j]^.MoveTo(0,0);
ScrollBox^.Insert(PackCbs[j]);
packtd:=NewTabDef(
cfg.pack[j].name,ScrollBox,
NewTabItem(sbsb,
NewTabItem(ScrollBox,
nil)),
packtd);
end;
New(Tab, Init(TabR,
NewTabDef('Gener~a~l',IlPath,
NewTabItem(TitleText,
NewTabItem(LabPath,
NewTabItem(ILPath,
NewTabItem(LabCfg,
NewTabItem(CfgCB,
nil))))),
packtd)
));
Tab^.GrowMode:=0;
Insert(Tab);
line:=tabr.b.y;
r.assign((width div 2)-18,line,(width div 2)-4,line+2);
new(okbut,init(r,'~C~ontinue',cmok,bfdefault));
Insert(OkBut);
r.assign((width div 2)+4,line,(width div 2)+14,line+2);
new(cancelbut,init(r,'~Q~uit',cmcancel,bfnormal));
Insert(CancelBut);
Tab^.Select;
end;
procedure tinstalldialog.handleevent(var event : tevent);
begin
if event.what=evcommand then
if event.command=cmquit then
begin
putevent(event);
event.command:=cmCancel;
end;
inherited handleevent(event);
end;
{*****************************************************************************
TSpecialInputLine
*****************************************************************************}
{ this should use AreAllFilesPresent if the base dir is changed...
but what if the installer has already choosen which files he wants ... }
procedure TSpecialInputLine.GetData(var Rec);
begin
inherited GetData(Rec);
end;
{*****************************************************************************
TApp
*****************************************************************************}
const
cmstart = 1000;
procedure tapp.do_installdialog;
var
p : pinstalldialog;
p3 : penddialog;
r : trect;
result,
c : word;
i,j : longint;
found : boolean;
{$ifndef Unix}
DSize,Space,ASpace : int64;
S: DirStr;
{$endif}
procedure doconfigwrite;
var
i : longint;
begin
for i:=1 to cfg.packs do
begin
if cfg.pack[i].defcfgfile<>'' then
writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].defcfgfile,cfg.defcfg,cfg.defcfgs,cfg.pack[i].targetname);
if cfg.pack[i].setpathfile<>'' then
writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].setpathfile,cfg.defsetpath,cfg.defsetpaths,cfg.pack[i].targetname);
end;
if haside then
begin
for i:=1 to cfg.packs do
if cfg.pack[i].defidecfgfile<>'' then
writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].defidecfgfile,cfg.defidecfg,cfg.defidecfgs,cfg.pack[i].targetname);
for i:=1 to cfg.packs do
if cfg.pack[i].defideinifile<>'' then
writedefcfg(data.basepath+cfg.pack[i].binsub+DirSep+cfg.pack[i].defideinifile,cfg.defideini,cfg.defideinis,cfg.pack[i].targetname);
if hashtmlhelp then
writehlpindex(data.basepath+DirSep+cfg.DocSub+DirSep+cfg.helpidx);
end;
end;
begin
data.basepath:=cfg.basepath;
data.cfgval:=0;
for j:=1 to cfg.packs do
data.packmask[j]:=high(sw_word);
repeat
{ select components }
p:=new(pinstalldialog,init);
c:=executedialog(p,@data);
if (c=cmok) then
begin
if Data.BasePath = '' then
messagebox('Please, choose the directory for installation first.',nil,mferror+mfokbutton)
else
begin
Data.BasePath := FExpand (Data.BasePath);
if Data.BasePath [Length (Data.BasePath)] = DirSep then
Dec (Data.BasePath [0]);
found:=false;
for j:=1 to cfg.packs do
if data.packmask[j]>0 then
found:=true;
if found then
begin
{$IFNDEF UNIX}
{ TH - check the available disk space here }
DSize := 0;
for j:=1 to cfg.packs do
with cfg.pack[j] do
begin
for i:=1 to packages do
begin
if data.packmask[j] and packagemask(i)<>0 then
begin
ASpace := package[i].diskspace;
if ASpace = -1 then
begin
MessageBox ('File ' + package[i].zip +
' is probably corrupted!', nil,
mferror + mfokbutton);
WriteLog ('File ' + package[i].zip +
' is probably corrupted!');
end
else Inc (DSize, ASpace);
end;
end;
end;
WriteLog ('Diskspace needed: ' + DotStr (DSize) + ' Kb');
S := Data.BasePath;
Space := DiskFree (byte (Upcase(S [1])) - 64);
{ -1 means that the drive is invalid }
if Space=-1 then
begin
WriteLog ('The drive ' + S [1] + ': is not valid');
if messagebox('The drive '+S[1]+': is not valid. Do you ' +
'want to change the installation path?',nil,
mferror+mfyesbutton+mfnobutton) = cmYes then
Continue;
Space:=0;
end;
Space := Space shr 10;
WriteLog ('Free space on drive ' + S [1] + ': ' +
DotStr (Space) + ' Kb');
if Space < DSize then
S := 'is not '
else
S := '';
if (Space < DSize + 500) then
begin
if S = '' then
S := 'might not be ';
if messagebox('There ' + S + 'enough space on the target ' +
'drive for all the selected components. Do you ' +
'want to change the installation path?',nil,
mferror+mfyesbutton+mfnobutton) = cmYes then
Continue;
end;
{$ENDIF}
if createinstalldir(data.basepath) then
break;
end
else
begin
{ maybe only config }
if (data.cfgval and 1)<>0 then
begin
result:=messagebox('No components selected.'#13#13'Create a configfile ?',nil,
mfinformation+mfyesbutton+mfnobutton);
if (result=cmYes) and createinstalldir(data.basepath) then
doconfigwrite;
exit;
end
else
begin
result:=messagebox('No components selected.'#13#13'Abort installation?',nil,
mferror+mfyesbutton+mfnobutton);
if result=cmYes then
exit;
end;
end;
end;
end
else
exit;
until false;
{ extract packages }
for j:=1 to cfg.packs do
with cfg.pack[j] do
begin
r.assign(10,7,70,18);
UnzDlg:=new(punzipdialog,init(r,'Extracting Packages'));
desktop^.insert(UnzDlg);
for i:=1 to packages do
begin
if data.packmask[j] and packagemask(i)<>0 then
begin
UnzDlg^.do_unzip(package[i].zip,data.basepath);
{ gather some information about the installed files }
if copy(package[i].zip,1,3)='ide' then
haside:=true;
if copy(package[i].zip,1,7)='doc-htm' then
begin
hashtmlhelp:=true;
{ correct the fpctoc file name if .html files are used }
if package[i].zip='doc-html.zip' then
if copy(cfg.helpidx,length(cfg.helpidx)-3,4)='.htm' then
cfg.helpidx:=cfg.helpidx+'l';
end;
end;
end;
desktop^.delete(UnzDlg);
dispose(UnzDlg,done);
end;
{ write config }
if (data.cfgval and 1)<>0 then
doconfigwrite;
{ show end message }
p3:=new(penddialog,init);
executedialog(p3,nil);
end;
procedure tapp.readcfg(const fn:string);
var
t : text;
i,j,k,
line : longint;
item,
s,hs : string;
params : array[0..0] of pointer;
{$ifndef FPC}
procedure readln(var t:text;var s:string);
var
c : char;
i : longint;
begin
c:=#0;
i:=0;
while (not eof(t)) and (c<>#10) do
begin
read(t,c);
if c<>#10 then
begin
inc(i);
s[i]:=c;
end;
end;
if (i>0) and (s[i]=#13) then
dec(i);
s[0]:=chr(i);
end;
{$endif}
begin
assign(t,StartPath + DirSep + fn);
{$I-}
reset(t);
{$I+}
if ioresult<>0 then
begin
StartPath := GetProgDir;
assign(t,StartPath + DirSep + fn);
{$I-}
reset(t);
{$I+}
if ioresult<>0 then
begin
params[0]:=@fn;
messagebox('File %s not found!',@params,mferror+mfokbutton);
WriteLog ('File "' + fn + '" not found!');
errorhalt;
end;
end;
line:=0;
while not eof(t) do
begin
readln(t,s);
inc(line);
if (s<>'') and not(s[1] in ['#',';']) then
begin
i:=pos('=',s);
if i>0 then
begin
item:=upper(Copy(s,1,i-1));
system.delete(s,1,i);
if item='VERSION' then
cfg.version:=s
else
if item='TITLE' then
cfg.title:=s
else
if item='BASEPATH' then
cfg.basepath:=s
else
if item='HELPIDX' then
cfg.helpidx:=s
else
if item='DOCSUB' then
cfg.docsub:=s
else
if item='DEFAULTCFG' then
begin
repeat
readln(t,s);
if upper(s)='ENDCFG' then
break;
if cfg.defcfgs<maxdefcfgs then
begin
inc(cfg.defcfgs);
cfg.defcfg[cfg.defcfgs]:=newstr(s);
end;
until false;
end
else
if item='DEFAULTIDECFG' then
begin
repeat
readln(t,s);
if upper(s)='ENDCFG' then
break;
if cfg.defidecfgs<maxdefcfgs then
begin
inc(cfg.defidecfgs);
cfg.defidecfg[cfg.defidecfgs]:=newstr(s);
end;
until false;
end
else
if item='DEFAULTSETPATH' then
begin
repeat
readln(t,s);
if upper(s)='ENDCFG' then
break;
if cfg.defsetpaths<maxdefcfgs then
begin
inc(cfg.defsetpaths);
cfg.defsetpath[cfg.defsetpaths]:=newstr(s);
end;
until false;
end
else
if item='DEFAULTIDEINI' then
begin
repeat
readln(t,s);
if upper(s)='ENDCFG' then
break;
if cfg.defideinis<maxdefcfgs then
begin
inc(cfg.defideinis);
cfg.defideini[cfg.defideinis]:=newstr(s);
end;
until false;
end
else
if item='PACK' then
begin
inc(cfg.packs);
if cfg.packs>maxpacks then
begin
MessageBox ('Too many packs!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'Too many packs');
close(log);
end;
halt(1);
end;
cfg.pack[cfg.packs].name:=s;
end
else
if item='CFGFILE' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
close(Log);
end;
halt(1);
end;
cfg.pack[cfg.packs].defcfgfile:=s
end
else
if item='IDECFGFILE' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
Close(Log);
end;
halt(1);
end;
cfg.pack[cfg.packs].defidecfgfile:=s
end
else
if item='SETPATHFILE' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
close(Log);
end;
halt(1);
end;
cfg.pack[cfg.packs].setpathfile:=s
end
else
if item='IDEINIFILE' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
Close(Log);
end;
halt(1);
end;
cfg.pack[cfg.packs].defideinifile:=s
end
else
if item='PPC386' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
Close(Log);
end;
halt(1);
end;
cfg.pack[cfg.packs].ppc386:=s;
end
else
if item='BINSUB' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
Close(Log);
end;
halt(1);
end;
cfg.pack[cfg.packs].binsub:=s;
end
{else: Obsolete PM }
{ if item='FILECHECK' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
WriteLn (Log, 'No pack set');
halt(1);
end;
cfg.pack[cfg.packs].filechk:=s;
end }
else
if item='TARGETNAME' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
Close(Log);
end;
halt(1);
end;
cfg.pack[cfg.packs].targetname:=s;
end
else
if item='PACKAGE' then
begin
if cfg.packs=0 then
begin
MessageBox ('No pack set found!', nil,
mfError + mfOkButton);
if CreateLog then
begin
WriteLn (Log, 'No pack set');
Close(Log);
end;
halt(1);
end;
with cfg.pack[cfg.packs] do
begin
j:=pos(',',s);
if (j>0) and (packages<maxpackages) then
begin
inc(packages);
hs:=copy(s,1,j-1);
k:=pos('[',hs);
if (k>0) then
begin
package[packages].zip:=Copy(hs,1,k-1);
package[packages].zipshort:=Copy(hs,k+1,length(hs)-k-1);
end
else
package[packages].zip:=hs;
package[packages].name:=copy(s,j+1,255);
end;
package[packages].diskspace:=-1;
end;
end
end;
end;
end;
close(t);
end;
procedure tapp.checkavailpack;
var
i, j : longint;
one_found : boolean;
begin
{ check the packages }
j:=0;
while (j<cfg.packs) do
begin
inc(j);
one_found:=false;
{if cfg.pack[j].filechk<>'' then}
for i:=1 to cfg.pack[j].packages do
begin
if file_exists(cfg.pack[j].package[i].zip,startpath) or
file_exists(cfg.pack[j].package[i].zipshort,startpath) then
begin
one_found:=true;
break;
end;
end;
if not one_found then
begin
{ remove the package }
move(cfg.pack[j+1],cfg.pack[j],sizeof(tpack)*(cfg.packs-j));
dec(cfg.packs);
dec(j);
end;
end;
end;
procedure tapp.initmenubar;
var
r : trect;
begin
getextent(r);
r.b.y:=r.a.y+1;
menubar:=new(pmenubar,init(r,newmenu(
newsubmenu('Free Pascal Installer',hcnocontext,newmenu(nil
),
nil))));
end;
procedure tapp.initstatusline;
var
R: TRect;
begin
GetExtent(R);
R.A.Y := R.B.Y - 1;
//R.B.X := R.B.X - 2;
New(StatusLine,
Init(R,
NewStatusDef(0, $EFFF,nil,nil
)
)
);
end;
procedure tapp.handleevent(var event : tevent);
begin
inherited handleevent(event);
if event.what=evcommand then
if event.command=cmstart then
begin
clearevent(event);
do_installdialog;
if successfull then
begin
event.what:=evcommand;
event.command:=cmquit;
handleevent(event);
end;
end;
end;
{$IFDEF DOSSTUB}
function CheckOS2: boolean;
var
OwnName: PathStr;
OwnDir: DirStr;
Name: NameStr;
Ext: ExtStr;
DosV, W: word;
P: PChar;
const
Title: string [15] = 'FPC Installer'#0;
RunBlock: TRunBlock = (Length: $32;
Dependent: 0;
Background: 0;
TraceLevel: 0;
PrgTitle: @Title [1];
PrgName: nil;
Args: nil;
TermQ: 0;
Environment: nil;
Inheritance: 0;
SesType: 2;
Icon: nil;
PgmHandle: 0;
PgmControl: 2;
Column: 0;
Row: 0;
Width: 80;
Height: 25);
begin
CheckOS2 := false;
asm
mov ah, 30h
int 21h
xchg ah, al
mov DosV, ax
mov ax, 4010h
int 2Fh
cmp ax, 4010h
jnz @0
xor bx, bx
@0:
mov W, bx
end;
if DosV > 3 shl 8 then
begin
OwnName := FExpand (ParamStr (0));
FSplit (OwnName, OwnDir, Name, Ext);
if (DosV >= 20 shl 8 + 10) and (W >= 20 shl 8 + 10) then
(* OS/2 version 2.1 or later running (double-checked) *)
begin
OwnName [Succ (byte (OwnName [0]))] := #0;
RunBlock.PrgName := @OwnName [1];
P := Ptr (PrefixSeg, $80);
if PByte (P)^ <> 0 then
begin
Inc (P);
RunBlock.Args := Ptr (PrefixSeg, $81);
end;
asm
mov ax, 6400h
mov bx, 0025h
mov cx, 636Ch
mov si, offset RunBlock
int 21h
jc @0
mov DosV, 0
@0:
end;
CheckOS2 := DosV = 0;
end;
end;
end;
{$ENDIF}
procedure usagescreen;
begin
writeln('FPC Installer ',installerversion,' ',installercopyright);
writeln('Command line options:');
writeln(' -l create log file');
{$ifdef MAYBE_LFN}
writeln(' --nolfn force installation with short file names');
{$endif MAYBE_LFN}
writeln;
writeln(' -h displays this help');
end;
var
OldExit: pointer;
procedure NewExit;
begin
ExitProc := OldExit;
if CreateLog then
begin
{$I-}
if ErrorAddr <> nil then
begin
WriteLn (Log, 'Installer crashed with RTE ', ExitCode);
Close (Log);
end
else
if ExitCode <> 0 then
begin
WriteLn (Log, 'Installer ended with non-zero exit code ', ExitCode);
Close (Log);
end
{$I+}
end;
end;
var
i : longint;
{ vm : tvideomode;}
begin
OldExit := ExitProc;
ExitProc := @NewExit;
{ register objects for help streaming }
RegisterWHTMLScan;
{$IFDEF OS2}
{ TH - no error boxes if checking an inaccessible disk etc. }
{$IFDEF FPC}
DosCalls.DosError (0);
{$ELSE FPC}
{$IFDEF VirtualPascal}
OS2Base.DosError (ferr_DisableHardErr);
{$ELSE VirtualPascal}
BseDos.DosError (0);
{$ENDIF VirtualPascal}
{$ENDIF FPC}
{$ENDIF}
{$IFDEF DOSSTUB}
if CheckOS2 then Halt;
{$ENDIF}
createlog:=false;
{$ifdef MAYBE_LFN}
locallfnsupport:=system.lfnsupport;
{$endif MAYBE_LFN}
for i:=1 to paramcount do
begin
if paramstr(i)='-l' then
createlog:=true
{$ifdef MAYBE_LFN}
else if paramstr(i)='--nolfn' then
begin
locallfnsupport:=false;
{$ifdef GO32V2}
{ lfnsupport is a const in win32 RTL }
system.lfnsupport:=locallfnsupport;
{$endif GO32V2}
end
{$endif MAYBE_LFN}
else if paramstr(i)='-h' then
begin
usagescreen;
halt(0);
end
else
begin
usagescreen;
halt(1);
end;
end;
if createlog then
begin
assign(log,'install.log');
rewrite(log);
{$ifdef MAYBE_LFN}
if not(locallfnsupport) then
WriteLog ('OS doesn''t have LFN support');
{$endif}
end;
getdir(0,startpath);
successfull:=false;
fillchar(cfg, SizeOf(cfg), 0);
fillchar(data, SizeOf(data), 0);
installapp.init;
{ vm.col:=80;
vm.row:=25;
vm.color:=true;
installapp.SetScreenVideoMode(vm);
}
FSplit (FExpand (ParamStr (0)), DStr, CfgName, EStr);
installapp.readcfg(CfgName + CfgExt);
installapp.checkavailpack;
{ installapp.readcfg(startpath+dirsep+cfgfile);}
{$ifdef GO32V2}
if not(lfnsupport) then
MessageBox('The operating system doesn''t support LFN (long file names),'+
' so some packages will get shorten filenames when installed',nil,mfinformation or mfokbutton);
{$endif}
installapp.do_installdialog;
installapp.done;
if createlog then
close(log);
end.